// TODO: CODE REVIEW & CLEANUP!
//
// Utilities.cs
//
// Implements miscellaneous utility types.
//

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Xml;
#if !SILVERLIGHT
using System.ServiceModel;
#endif
using HomeUX.Common;


namespace HomeUX.Utilities
{

/// <summary>
/// Static utility methods.
/// </summary>
///
public static class Util
{
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Encryption
    //

    /// <summary>
    /// The number of bytes in combined client salt + server salt.
    /// </summary>
    public const int SaltLength = 16;

    /// <summary>
    /// The number of bytes of entropy included in strings encrypted using <r>ProtectString</r>
    /// and <r>UnprotectString</r>.
    /// </summary>
    const int EntropyLength = 16;

    /// <summary>
    /// Generates a cryptographic salt value that's half the length specified by <r>SaltLength</r>.
    /// </summary>
    ///
    /// <remarks>
	/// <para>
	/// HomeUX uses an encryption block size of <r>SaltLength</r> bytes. That means that the
	/// initialization vector (IV) must be must also be <r>SaltLength</r> bytes.  The same value is
	/// used as password salt.  To improve security, the first half of the salt value is generated
	/// by the client, and the second half bytes is generated by the server.
	/// <r>GenerateHalfSalt</r> method is used to generate both the client half-salt value and the
	/// server half-salt value; <r>CombineSalt</r> combines the two.
	/// </para>
	/// <para>
	/// Within each half-salt byte array, the first half is based on the current time, and the
	/// second half is random data.  The result is highly likely to be a "nonce".
	/// </para>
	/// </remarks>
	///
    public static byte[] GenerateHalfSalt()
    {
        // set <halfSalt> to SaltLength bytes of random data -- we'll only use the first half
        var halfSalt = new byte[SaltLength / 2];
        (new RNGCryptoServiceProvider()).GetBytes(halfSalt);

        // set the first SaltLength / 4 bytes of <halfSalt> to the the lower 32 bits of the number
		// of seconds since midnight of January 1, 2000, UTC
        uint seconds = (uint)(
			(long)(DateTime.UtcNow - new DateTime(2000, 1, 1)).TotalSeconds & 0xFFFFFFFF);
        for (int i = SaltLength / 4 - 1; i >= 0; i--)
        {
            halfSalt[i] = (byte)(seconds & 0xFF);
            seconds = seconds >> 8;
        }

		// done
		return halfSalt;
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="clientSalt">TODO</param>
    ///
    /// <param name="serverSalt">TODO</param>
    ///
    public static byte[] CombineSalt(byte[] clientSalt, byte[] serverSalt)
    {
        // check the argument lengths
        if (clientSalt.Length != SaltLength / 2)
        {
            throw new ArgumentException(String.Format(
                "Client salt must be {0} bytes long", SaltLength / 2), "clientSalt");
        }
        if (serverSalt.Length != SaltLength / 2)
        {
            throw new ArgumentException(String.Format(
                "Server salt must be {0} bytes long", SaltLength / 2), "serverSalt");
        }

        // combine the half-salt values
        byte[] salt = new byte[SaltLength];
        Array.Copy(clientSalt, 0, salt, 0, SaltLength / 2);
        Array.Copy(serverSalt, 0, salt, SaltLength / 2, SaltLength / 2);
        return salt;
    }

    /// <summary>
    /// Parses a string containing a half-salt value (i.e. client salt or server salt) and returns
    /// the corresponding byte array.
    /// </summary>
    ///
    /// <param name="halfSaltString">The string to parse.</param>
    /// 
    /// <exception cref="FormatException">
    /// <pr>halfSaltString</pr> isn't a valid base 64 string, or the resulting byte array isn't
    /// the correct length for a half-salt value.
    /// </exception>
    ///
    public static byte[] ParseHalfSaltString(string halfSaltString)
    {
        byte[] halfSalt = Convert.FromBase64String(halfSaltString);
        if (halfSalt.Length != SaltLength / 2)
            throw new FormatException("Incorrect half-salt length");
        return halfSalt;
    }

    // converts a salt byte array into it string form
    public static string SaltToString(byte[] salt)
    {
        return Convert.ToBase64String(salt);
    }

#if !SILVERLIGHT

    /// <summary>
    /// Encrypts a string using the current user's credentials.
    /// </summary>
	///
    /// <param name="plainTextString">The string to encrypt.</param>
	///
    /// <param name="scope">The <n>DataProtectionScope</n> to use for protecting the string.  This
    ///     determines if the encrypted string can only be decrypted by code running under the
    ///     current user's credentials, or if the string can be decrypted by any process running
    ///     on the current computer.</param>
    ///
    /// <returns>
	/// The encrypted string.
	/// </returns>
	///
	public static string ProtectString(string plainTextString, DataProtectionScope scope)
	{
		// convert the plain-text string into bytes, stored in <decrypted>
		byte[] decrypted = Encoding.ASCII.GetBytes(plainTextString);

		// encrypt <decrypted>; store the result in <encrypted>
		RandomNumberGenerator rng = RandomNumberGenerator.Create();
		byte[] entropy = new byte[EntropyLength];
		rng.GetNonZeroBytes(entropy);
		byte[] encrypted = ProtectedData.Protect(decrypted, entropy, scope);

		// convert the encrypted string to base 64 and return it
		byte[] encryptedPlusEntropy = new byte[encrypted.Length + entropy.Length];
		encrypted.CopyTo(encryptedPlusEntropy, 0);
		entropy.CopyTo(encryptedPlusEntropy, encrypted.Length);
		return Convert.ToBase64String(encryptedPlusEntropy);
	}

    /// <summary>
    /// Decrypts a string using the current user's credentials.
    /// </summary>
	///
    /// <param name="encryptedString">The string to decrypt.  This string must have been encrypted
	/// 	using <c>EncryptString</c>.</param>
	///
    /// <param name="scope">The value of <pr>scope</pr> passed to <r>ProtectString</r>.</param>
    /// 
    /// <returns>
	/// The decrypted string.
	/// </returns>
	///
	public static string UnprotectString(string encryptedString, DataProtectionScope scope)
	{
		// convert the encrypted password from base 64 to bytes, stored in <encrypted> and
		// <entropy>
		byte[] encryptedPlusEntropy = Convert.FromBase64String(encryptedString);
		if (encryptedPlusEntropy.Length <= EntropyLength)
			throw new ArgumentException("Invalid encrypted string");
		byte[] encrypted = new byte[encryptedPlusEntropy.Length - EntropyLength];
		Array.Copy(encryptedPlusEntropy, 0, encrypted, 0, encrypted.Length);
		byte[] entropy = new byte[EntropyLength];
		Array.Copy(encryptedPlusEntropy, encrypted.Length, entropy, 0, entropy.Length);

		// decrypt <encrypted> in-place; store the result into <decrypted>
		byte[] decrypted = ProtectedData.Unprotect(encrypted, entropy, scope);

		// convert <decrypted> to ASCII and return the result
		return Encoding.ASCII.GetString(decrypted, 0, decrypted.Length);
	}

#endif

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Cluster Processing
    //

	/// <summary>
	/// A delegate that returns the "cluster key" of an item in a collection, when used with
	/// <r>EnumerateClusters</r>.
	/// </summary>
	///
	/// <typeparam name="ItemType">The type of an item in the collection.</typeparam>
	///
	/// <typeparam name="ClusterKeyType">The type of the caller-defined "cluster key" for items in
	/// 	the collection.</typeparam>
	///
	/// <param name="item"></param>
	///
	public delegate ClusterKeyType GetClusterKeyDelegate<ItemType, ClusterKeyType>(ItemType item);

	/// <summary>
	/// A delegate that's called at the beginning of a cluster of items in a collection, when used
	/// with <r>EnumerateClusters</r>.
	/// </summary>
	///
	/// <typeparam name="ClusterKeyType">The type of the caller-defined "cluster key" for items in
	/// 	the collection.</typeparam>
	///
	/// <param name="clusterKey">The "cluster key" of the cluster that's beginning.</param>
	///
	public delegate void StartOfClusterDelegate<ClusterKeyType>(ClusterKeyType clusterKey);

	/// <summary>
	/// Called once for each item in a collection when used with <r>EnumerateClusters</r>.
	/// </summary>
	///
	/// <typeparam name="ItemType">The type of an item in the collection.</typeparam>
	///
	/// <typeparam name="ClusterKeyType">The type of the caller-defined "cluster key" for items in
	/// 	the collection.</typeparam>
	///
	/// <param name="item">The item in the collection.</param>
	///
	/// <param name="clusterKey">The "cluster key" of the current cluster, i.e. the cluster
	/// 	containing this item.  This cluster key is the same value returned by
	/// 	<r>GetClusterKeyDelegate{,}</r> for this item.</param>
	///
	public delegate void ProcessClusterItemDelegate<ItemType, ClusterKeyType>(ItemType item, ClusterKeyType clusterKey);

	/// <summary>
	/// A delegate that's called at the end of a cluster of items in a collection, when used with
	/// <r>EnumerateClusters</r>.
	/// </summary>
	///
	/// <typeparam name="ClusterKeyType">The type of the caller-defined "cluster key" for items in
	/// 	the collection.</typeparam>
	///
	/// <param name="clusterKey">The "cluster key" of the cluster that's ending.</param>
	///
	public delegate void EndOfClusterDelegate<ClusterKeyType>(ClusterKeyType clusterKey);

	/// <summary>
	/// Iterates over an <r>IEnumerable</r> collection, calling a pair of delegates for each item
	/// and another pair for each cluster of items that all have the same caller-defined "cluster
	/// key".
	/// </summary>
	///
	/// <typeparam name="ItemType">The type of an item in the collection.</typeparam>
	///
	/// <typeparam name="ClusterKeyType">The type of the caller-defined "cluster key" for items in
	/// 	the collection.</typeparam>
	///
	/// <param name="collection">The collection to enumerate through.</param>
	///
	/// <param name="getClusterKeyDelegate">A delegate which, given an item in the collection,
	/// 	returns that item's cluster key.</param>
	///
	/// <param name="startOfClusterDelegate">A delegate that's called at the beginning of a
	/// 	cluster.</param>
	///
	/// <param name="processItemDelegate">A delegate that's called once for each item in the
	/// 	collection.</param>
	///
	/// <param name="endOfClusterDelegate">A delegate that's called at the end of a cluster.
	/// 	</param>
	///
	/// <remarks>
	/// <para>
	/// The intent of <r>EnumerateClusters</r> is to simplify end-of-loop logic and reduce code
	/// duplication and common coding errors for code that walks through a collection and performs
	/// some action on each cluster of items that are related in some way.
	/// </para>
	/// <para>
	/// <r>EnumerateClusters</r> enumerates over a collection that implements
	/// <r>System.Collections.IEnumerable</r>.  Items in the collection are of type
	/// <tpr>ItemType</tpr>.  For each item, the caller must be able to identify a "cluster key"
	/// (a value of type <tpr>ClusterKeyType</tpr>) defined so that items with the same cluster key
	/// are clustered together in the enumeration.  (In other words, the collection must be sorted
	/// by cluster key.)
	/// </para>
	/// <para>
	/// For each item, <r>EnumerateClusters</r> calls <pr>getClusterKeyDelegate</pr> to retrieve
	/// the item's cluster key, and then <pr>processItemDelegate</pr> is called.
	/// <pr>startOfClusterDelegate</pr> is called at the beginning of each cluster (before the call
	/// to <pr>processItemDelegate</pr> for that item), and <pr>endOfClusterDelegate</pr> is called
	/// at the end of each cluster.
	/// </para>
	/// </remarks>
	///
	public static void EnumerateClusters<ItemType, ClusterKeyType>(
		System.Collections.IEnumerable collection,
		GetClusterKeyDelegate<ItemType, ClusterKeyType> getClusterKeyDelegate,
		StartOfClusterDelegate<ClusterKeyType> startOfClusterDelegate,
		ProcessClusterItemDelegate<ItemType, ClusterKeyType> processItemDelegate,
		EndOfClusterDelegate<ClusterKeyType> endOfClusterDelegate)
	{
		bool firstItem = true;
		ClusterKeyType currentClusterKey = default(ClusterKeyType);
		foreach (ItemType item in collection)
		{
			ClusterKeyType key = getClusterKeyDelegate(item);
			if (firstItem)
			{
				// this is the first item in the first cluster
				firstItem = false;
				currentClusterKey = key;
				startOfClusterDelegate(key);
				processItemDelegate(item, key);
			}
			else
			if (key.Equals(currentClusterKey))
			{
				// this is another item in the current cluster
				processItemDelegate(item, key);
			}
			else
			{
				// this is the start of a new cluster
				endOfClusterDelegate(currentClusterKey);
				currentClusterKey = key;
				startOfClusterDelegate(key);
				processItemDelegate(item, key);
			}
		}
		if (!firstItem)
		{
			// if the collection wasn't empty, there was at least one cluster, so end the last
			// cluster
			endOfClusterDelegate(currentClusterKey);
		}
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Instance Construction
    //

    /// <summary>
    /// The list of assembly resolvers registered using <r>RegisterAssemblyResolver</r>.
    /// </summary>
    static List<Func<string, Assembly>> _assemblyResolvers = new List<Func<string, Assembly>>();

    /// <summary>
    /// Registers an "assembly resolver" method to be called when <r>CreateInstance</r> is called.
    /// The assembly resolver is given the path to an assembly DLL; the resolver may return either
    /// an <n>Assembly</n> object representing the assembly, or <n>null</n> if the assembly isn't
    /// known to the resolver.
    /// </summary>
    /// 
    /// <remarks>
    /// Assembly resolvers are used primarily to implement server simulation within a Silverlight
    /// client.
    /// </remarks>
    ///
    /// <param name="assemblyResolver">The assembly resolver method to register.  The parameter is
    ///     the path to an assembly DLL (absolute, or relative to the the directory containing the
	/// 	currently executing assembly); the return value is an <n>Assembly</n> object
	/// 	representing the assembly, or <n>null</n> if the assembly is not found.</param>
    ///
    public static void RegisterAssemblyResolver(Func<string, Assembly> assemblyResolver)
    {
        _assemblyResolvers.Add(assemblyResolver);
    }

    /// <summary>
    /// Creates an instance of a given type that's implemented in a specified .dll file, using
    /// information in a provided "construction specification".  Returns a reference to the
    /// instance, cast to the same or a different type (for example, an interface).  A single
    /// uniform exception is thrown for most error conditions.
    /// </summary>
    /// 
    /// <typeparam name="T">The type of object to return.</typeparam>
    ///
    /// <param name="constructionSpec">The "construction specification", which consists of two or
    /// 	three parts, separated by semicolon (;) characters: the path to the DLL (absolute, or
    /// 	relative to the the directory containing the currently executing assembly); the name
    /// 	of the type to create (see the <i>typeName</i> parameter in the 3-parameter overload
    /// 	of <r>CreateInstance</r>); the string array to use as an argument to the constructor
    ///     (see the <i>constructorArguments</i> parameter in the 3-parameter overload of
    /// 	<r>CreateInstance</r>).  If only two parts are present, a constructor with no
    /// 	parameters is used.</param>
    ///
    /// <exception cref="CreateInstanceException">
    /// See the 3-parameter overload of <r>CreateInstance</r> for more the potential causes of
    /// this exception.  Additionally, this exception is thrown if the format of
    /// <pr>constructionSpec</pr> is incorrect.
    /// </exception>
    ///
    /// <remarks>
    /// See the 3-parameter overload of <r>CreateInstance</r> for more information.
    /// </remarks>
    ///
    public static T CreateInstance<T>(string constructionSpec)
    {
        string[] parts = constructionSpec.Split(';');
        string dllRelativePath, typeName;
        string[] constructorArguments;
        if (parts.Length == 1)
        {
            dllRelativePath = parts[0];
            typeName = null;
            constructorArguments = null;
        }
        else
        if (parts.Length == 2)
        {
            dllRelativePath = parts[0];
            typeName = parts[1];
            constructorArguments = null;
        }
        else
        if (parts.Length >= 3)
        {
            dllRelativePath = parts[0];
            typeName = parts[1];
            if ((parts.Length > 3) || (parts[2].Length > 0)) // check for empty third part
            {
                constructorArguments = new string[parts.Length - 2];
                Array.Copy(parts, 2, constructorArguments, 0, constructorArguments.Length);
            }
            else
                constructorArguments = null;
        }
        else
        {
            throw new CreateInstanceException(String.Format(
                "Invalid construction specification: {0}", constructionSpec));
        }

#if SILVERLIGHT
        string dllAbsolutePath = dllRelativePath;
#else
		string dllAbsolutePath;
        try
        {
            dllAbsolutePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(
                Assembly.GetExecutingAssembly().Location), dllRelativePath));
        }
        catch (Exception ex)
        {
            if ((ex is IOException) || (ex is ArgumentException) || (ex is NotSupportedException))
                throw new CreateInstanceException(String.Format(
                    "Cannot determine location of file: {0}", dllRelativePath));
            else
                throw;
        }

        if (!File.Exists(dllAbsolutePath))
        {
            throw new CreateInstanceException(String.Format(
                "DLL file not found: {0}", dllAbsolutePath));
        }
#endif

        return CreateInstance<T>(dllAbsolutePath, typeName, constructorArguments);
    }

    /// <summary>
    /// Creates an instance of a given type that's implemented in a specified .dll file.  Returns a
    /// reference to the instance, cast to the same or a different type (for example, an
    /// interface).  A single uniform exception is thrown for most error conditions.
    /// </summary>
    ///
    /// <typeparam name="T">The type to cast the result to.  This may be the same as
    /// 	<pr>typeName</pr>, or it may be a base class of <pr>typeName</pr> or an interface
    /// 	implemented by <pr>typeName</pr>.</typeparam>
    ///
    /// <param name="dllPath">The full path to the DLL containing the type to create an instance
    /// 	of.</param>
    ///
    /// <param name="typeName">The name of the type to create an instance of.  If this name
    ///     contains a period (.) it is treated as a fully qualified type name; if not, then the
    ///     assembly is searched for a type with this <n>Type.Name</n>.  If this parameter is
    /// 	<n>null</n> or <n>String.Empty</n>, the type with the same name as the base file name
    /// 	of <pr>dllPath</pr>, without its extension, is used.</param>
    ///
    /// <param name="constructorArguments">The string array to use as an argument to the
    ///     constructor.  If not <n>null</n>, a constructor that accepts a string array parameter
    ///     is found.  If <n>null</n>, a constructor with zero parameters is found.</param>
    /// 
    /// <returns>
    /// An instance of type <pr>typeName</pr> loaded from <pr>dllPath</pr>, cast to <tpr>T</tpr>.
    /// </returns>
    ///
    /// <exception cref="CreateInstanceException">
    /// One of the following conditions occurred:
    /// <list type="bullet">
    /// <item><description>
    /// 	The path specified by <pr>dllPath</pr> isn't a full path, or doesn't refer to a valid
    /// 	DLL.
    /// </description></item>
    /// <item><description>
    /// 	The type specified by <pr>typeName</pr> isn't implemented in the DLL, or isn't public,
    /// 	or doesn't contain an appropriate constructor (see <pr>constructorArguments</pr>).
    /// </description></item>
    /// <item><description>
    /// 	More than one type with the specified name was found.
    /// </description></item>
    /// <item><description>
    /// 	An exception occurred when the constructor was invoked.
    /// </description></item>
    /// </list>
    /// </exception>
    ///
    public static T CreateInstance<T>(string dllPath, string typeName,
        string[] constructorArguments)
    {
        // if <typeName> isn't provided, base it on <dllName>
        if (String.IsNullOrEmpty(typeName))
            typeName = Path.GetFileNameWithoutExtension(dllPath);

        // call the registered assembly resolvers (if any) to try to resolve <dllPath> (e.g.
        // "Foo.dll") to an assembly
        Assembly assembly = null;
        foreach (Func<string, Assembly> assemblyResolver in _assemblyResolvers)
        {
            if ((assembly = assemblyResolver(dllPath)) != null)
                break;
        }

        if (assembly == null)
        {
#if SILVERLIGHT
            throw new CreateInstanceException(String.Format("Cannot find assembly \"{0}\"",
                dllPath));
#else
            try
            {
                assembly = LoadAssemblyFile(dllPath);
            }
            catch (LoadAssemblyException ex)
            {
                throw new CreateInstanceException(dllPath, typeName, ex.InnerException);
            }
#endif
        }

        // load the specified type
        Type type;
        if (typeName.Contains("."))
        {
            // <typeName> contains a period, so treat it as a fully qualified type name
            try
            {
                type = assembly.GetType(typeName, true);
            }
            catch (TypeLoadException ex)
            {
                throw new CreateInstanceException(dllPath, typeName, ex);
            }
        }
        else
        {
            // <typeName> doesn't contain a period, so look for a type with this name
            IEnumerable<Type> types;
            try
            {
                types = assembly.GetTypes().Where(t => t.Name == typeName);
            }
            catch (ReflectionTypeLoadException ex)
            {
                var details = new StringBuilder(1000);
                foreach (Exception ex2 in ex.LoaderExceptions)
                    details.AppendFormat("\r\n{0}", ex2.Message);
                throw new CreateInstanceException(dllPath, typeName, null,
                    String.Format("TODO:Resource:Failed to load type information: {0}{1}",
                        ex.Message, details));
            }
            int count = types.Count();
            if (count != 1) // error if there isn't exactly one type with this name
            {
                throw new CreateInstanceException(dllPath, typeName, null,
                    String.Format("TODO:Resource:Found {0} type(s) named \"{1}\"",
                        count, typeName));
            }
            type = types.First();
        }

        // locate a constructor of the specified type
        ConstructorInfo constructorInfo;
        if (constructorArguments != null)
            constructorInfo = type.GetConstructor(new Type[] { typeof(String[]) });
        else
            constructorInfo = type.GetConstructor(Type.EmptyTypes);
        if (constructorInfo == null)
            throw new CreateInstanceException(dllPath, typeName, null,
                CommonResources.CreateInstance_NoConstructor);

        // create an instance of the specified type using the located constructor
        T instance;
        try
        {
            object instanceAsObject;
            if (constructorArguments != null)
                instanceAsObject = constructorInfo.Invoke(new object[] { constructorArguments });
            else
                instanceAsObject = constructorInfo.Invoke(null);
            instance = (T)instanceAsObject;
        }
        catch (TargetInvocationException ex)
        {
            Exception inner = ex.InnerException ?? ex;
            throw new CreateInstanceException(dllPath, typeName, ex,
                String.Format(CommonResources.CreateInstance_ExceptionFromConstructor,
                    inner.GetType().Name, inner.Message));
        }

        return instance;
    }

#if !SILVERLIGHT
    /// <summary>
    /// Loads an assembly given a path to a DLL file.  A single uniform exception is thrown for
	/// most error conditions.
    /// </summary>
	///
    /// <param name="dllPath">The full path to the DLL to load.</param>
	///
	/// <exception cref="CreateInstanceException">
	/// The path specified by <pr>dllPath</pr> isn't a full path, or doesn't refer to a valid DLL.
	/// </exception>
	///
    public static Assembly LoadAssemblyFile(string dllPath)
    {
        try
        {
            return Assembly.LoadFile(dllPath);
        }
        catch (ArgumentException ex)
        {
			throw new LoadAssemblyException(dllPath, ex);
        }
        catch (FileLoadException ex)
        {
            throw new LoadAssemblyException(dllPath, ex);
        }
        catch (FileNotFoundException ex)
        {
            throw new LoadAssemblyException(dllPath, ex);
        }
        catch (BadImageFormatException ex)
        {
            throw new LoadAssemblyException(dllPath, ex);
        }
    }
#endif

#if !SILVERLIGHT

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Console Coloring
    //

    /// <summary>
	/// Sets the console foreground color to a given color, and returns an <n>IDisposable</n>
	/// object which, when <n>Dispose</n> is called, resets the color.  Intended for use in a
	/// code block such as <c>using (DnUtil.SetConsoleForegroundColor()) { ... }</c>.
    /// </summary>
    /// 
    /// <param name="color">The color to use.</param>
	///
	public static IDisposable SetConsoleForegroundColor(ConsoleColor color)
	{
        // set <restore> to an IDisposable implementation which will restore the foreground color
		// to its original value when IDisposable.Dispose is called
        IDisposable restore = new RestoreConsoleColors()
        {
            ForegroundColor = Console.ForegroundColor
        };

		// set the foreground color to the desired color
		Console.ForegroundColor = color;

		// done
        return restore;
	}

    /// <summary>
	/// Swaps the console foreground and background colors, and returns an <n>IDisposable</n>
	/// object which, when <n>Dispose</n> is called, resets the colors.  Intended for use in a
	/// code block such as <c>using (DnUtil.ConsoleReverseVideo()) { ... }</c>.
    /// </summary>
	///
	public static IDisposable ConsoleReverseVideo()
	{
        // set <restore> to an IDisposable implementation which will restore the foreground and
        // background colors to their original values when IDisposable.Dispose is called
        var restore = new RestoreConsoleColors()
        {
            ForegroundColor = Console.ForegroundColor,
            BackgroundColor = Console.BackgroundColor
        };

		// set the foreground and background colors to the desired color
		Console.ForegroundColor = restore.BackgroundColor.Value;
		Console.BackgroundColor = restore.ForegroundColor.Value;

		// done
        return restore;
	}

    /// <summary>
    /// Sets the console foreground and/or background colors to given colors when
	/// <n>IDisposable.Dispose</n> is called.
    /// </summary>
    ///
    class RestoreConsoleColors : IDisposable
    {
		///////////////////////////////////////////////////////////////////////////////////////////
		// Public Properties
		//

        /// <summary>
        /// The foreground color to switch to when <n>IDisposable.Dispose</n> is called, or
		/// <n>null</n> to leave the foreground color as-is.
        /// </summary>
        public ConsoleColor? ForegroundColor { get; set; }

        /// <summary>
        /// The background color to switch to when <n>IDisposable.Dispose</n> is called, or
		/// <n>null</n> to leave the background color as-is.
        /// </summary>
        public ConsoleColor? BackgroundColor { get; set; }

		///////////////////////////////////////////////////////////////////////////////////////////
		// IDisposable Implementation
		//
        
        void IDisposable.Dispose()
        {
            if (ForegroundColor.HasValue)
				Console.ForegroundColor = ForegroundColor.Value;
            if (BackgroundColor.HasValue)
				Console.BackgroundColor = BackgroundColor.Value;
        }
    }

#if false
    /// <summary>
	/// Implements <n>IDisposable</n> which, when <n>Dispose</n> is called, calls
    /// <n>Console.ResetColor</n>.
    /// </summary>
	///
	class ResetConsoleColor : IDisposable
	{
		void IDisposable.Dispose()
		{
            Console.ResetColor();
		}
	}
#endif

#endif

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Tracing
    //

    static int _traceCounter;

    public static bool IsShowHighlightOnly { set; get; }

    public static void TraceBare(bool highlight, string text)
    {
#if SILVERLIGHT
        Debug.WriteLine("{0}", text);
#else
        if (highlight && !IsShowHighlightOnly)
        {
            using (ConsoleReverseVideo())
                Debug.Write(text);
            Debug.WriteLine(String.Empty);
        }
        else
            Debug.WriteLine(text);
#endif
    }

    public static void Trace(string format, params object[] args)
    {
        Trace(false, format, args);
    }

    public static void Trace(bool highlight, string format, params object[] args)
    {
        int traceCounter = Interlocked.Increment(ref _traceCounter);

        if (IsShowHighlightOnly && !highlight)
            return;
        
        string prefix = String.Format("[{0}] ", traceCounter);
        string text = Util.Format(format, args);
        text = text.Replace("\r\n", "\n").Replace("\r", "\n");
        string prefixBlanks = null;
        bool isFirstLine = true;
        foreach (string line in text.Split('\n'))
        {
            if (isFirstLine)
            {
                TraceBare(highlight, prefix + line);
                isFirstLine = false;
            }
            else
            {
                if (prefixBlanks == null)
                    prefixBlanks = new String(' ', prefix.Length);
                TraceBare(highlight, prefixBlanks + line);
            }
        }
    }

    public static void TraceBlock(string blockText, string headerFormat, params object[] headerArgs)
    {
        TraceBlock(false, blockText, headerFormat, headerArgs);
    }

    public static void TraceBlock(bool highlight, string blockText, string headerFormat, params object[] headerArgs)
    {
        int traceCounter = Interlocked.Increment(ref _traceCounter);

        if (IsShowHighlightOnly && !highlight)
            return;

        string header = Format(headerFormat, headerArgs);
        Util.TraceBare(highlight, Format("[{0}]\n  _____/ {1} \\_____\n /\n| {2}", traceCounter, header,
            blockText.Replace("\r\n", "\n").Replace("\n", "\n| ") + "\n \\" + new String('_', 14 + header.Length)));
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Formatting
    //

    /// <summary>
    /// Returns the concatenation of the message of a given exception and all its nested inner
    /// exceptions.
    /// </summary>
    ///
    /// <param name="ex">The exception.</param>
    ///
    public static string FormatExceptionMessage(Exception ex)
    {
        return FormatExceptionMessage(ex, false);
    }

    /// <summary>
    /// Returns the concatenation of the message of a given exception and all its nested inner
    /// exceptions.
    /// </summary>
    ///
    /// <param name="ex">The exception.</param>
    /// 
    /// <param name="includeExceptionName">If <n>true</n>, the name of each exception is included
    ///     in the returned string.</param>
    ///
    public static string FormatExceptionMessage(Exception ex, bool includeExceptionName)
    {
        var message = new StringBuilder(100);
        while (ex != null)
        {
            if (message.Length > 0)
                message.AppendLine();
            message.Append(ex.Message);
            if (includeExceptionName)
                message.AppendFormat(" [{0}]", ex.GetType().Name);
            ex = ex.InnerException;
        }
        return message.ToString();
    }

    /// <summary>
    /// Formats a string using <n>String.Format</n>, except that if no arguments are provided
    /// then the format string is returned as-is, without formatting.
    /// </summary>
    ///
    /// <param name="format">The format string.</param>
    ///
    /// <param name="args">Formatting arguments.  If no arguments are provided, <pr>format</pr> is
    ///     returned as-is, without formatting.</param>
    ///
    /// <remarks>
    /// This method is like <n>String.Format</n>, but if <pr>args</pr> is <n>null</n> or empty then
	/// this method just returns <pr>format</pr>.  For example, suppose a method
	/// <c>Foo(string format, params object[] args)</c> which (among other things) does
	/// <c>String.Format(format, args)</c>, and somewhere in your code you call <c>Foo(str)</c>.
	/// If <c>str</c> can be an arbitrary string, you'll get an error if <c>str</c> contains
	/// braces.  But if Foo calls <c>Util.Format(format, args)</c> instead of
	/// <c>String.Format(format, args)</c> that won't happen.
	/// </remarks>
    ///
    public static string Format(string format, params object[] args)
    {
        if ((args == null) || (args.Length == 0))
            return format;
        else
            return String.Format(format, args);
    }

    public static string FormatDuration(double seconds)
    {
        return FormatDuration((int)seconds);
    }

    public static string FormatDuration(int seconds)
    {
        int min = seconds / 60;
        int sec = seconds % 60;
        if (min < 60)
            return String.Format("{0}:{1:00}", min, sec);
        else
            return String.Format("{0}:{1:00}:{2:00}", min / 60, min % 60, sec);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Conversions
    //

    /// <summary>
    /// Converts the bytes of this <n>ArraySegment</n> to a string, assuming UTF-8 encoding.
    /// </summary>
    ///
    /// <param name="buffer">The range of bytes to convert.</param>
    ///
    public static string Utf8ToString(ArraySegment<byte> buffer)
    {
        return Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
    }

    /// <summary>
    /// Converts this string to a UTF-8-encoded byte array.
    /// </summary>
    ///
    /// <param name="value">The string to convert.</param>
    ///
    public static byte[] ToUtf8(string value)
    {
        return Encoding.UTF8.GetBytes(value);
    }

    public static bool TryXmlConvert(string stringValue, out int intValue)
    {
        try
        {
            intValue = XmlConvert.ToInt32(stringValue);
            return true;
        }
        catch (Exception ex)
        {
            if ((ex is FormatException) || (ex is OverflowException))
            {
                intValue = 0;
                return false;
            }
            else
                throw;
        }
    }

    /// <summary>
    /// Parses the XML representation of a boolean value.
    /// </summary>
    ///
    /// <param name="stringValue">The string to parse.</param>
    ///
    /// <param name="defaultValue">The value to return if <pr>stringValue</pr> is <n>null</n> or
    ///     isn't a valid boolean value.</param>
    ///
    public static bool ParseXmlBool(string stringValue, bool defaultValue)
    {
        if (stringValue == null)
            return defaultValue;
        try
        {
            return XmlConvert.ToBoolean(stringValue);
        }
        catch (FormatException)
        {
            return defaultValue;
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Computer Name
    //

    /// <summary>
    /// Contains the cached value of <r>ComputerName</r>, or <n>null</n>if <r>ComputerName</r>
    /// hasn't been accessed yet.
    /// </summary>
    static string _computerName;

    /// <summary>
    /// Returns the name of this computer.  In a Silverlight application, "localhost" will be
    /// returned.
    /// </summary>
    ///
    public static string ComputerName
    {
        get
        {
            if (_computerName == null)
            {
#if SILVERLIGHT
                _computerName = "localhost";
#else
                _computerName = Environment.MachineName;
#endif
            }

            return _computerName;
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Miscellaneous
    //

	/// <summary>
	/// Gets an enumeration of all indices of a given array.
	/// </summary>
    /// 
    /// <typeparam name="T">The type of elements in the array.</typeparam>
    /// 
    /// <param name="array">The array to enumerate indices of.</param>
	///
	static public IEnumerable<int> IndicesOf<T>(params T[] array)
	{
        for (int index = 0; index < array.Length; index++)
			yield return index;
	}

    /// <summary>
    /// Splits a string at given delimiters, and removes leading and trailing white space from each
	/// returned part of the string.
    /// </summary>
    ///
    /// <param name="value">The string to split.</param>
    /// 
    /// <param name="separator">The separator to split at.</param>
    /// 
    /// <returns>
    /// An array containing the trimmed split parts.  For example, if <pr>value</pr> is <c>"abc,
	/// def , ,ghi "</c> and <pr>separator</pr> is <c>','</c>, the return value is an array
	/// containing elements <c>"abc"</c>, <c>"def"</c>, <c>""</c>, and <c>"ghi"</c>.
    /// </returns>
    ///
    static public string[] SplitAndTrim(string value, char separator)
    {
        string[] parts = value.Split(separator);
        foreach (int index in IndicesOf(parts))
            parts[index] = parts[index].Trim();
        return parts;
    }

    /// <summary>
    /// Returns a string that can be used within a <c>[DebuggerDisplay]</c> attribute for displaying
    /// the status of a lock object.
    /// </summary>
    ///
    /// <param name="lockObject">The lock object, i.e. an object intended for use as
    ///     "<c>lock (lockObject)</c>".</param>
    ///
    /// <returns>
    /// A string suitable for use within a <c>[DebuggerDisplay]</c> attribute.
    /// </returns>
    /// 
    /// <remarks>
    /// Warning: this is not a fast method!  It creates a new thread purely for the purpose of
    /// determining the status of a lock.  This should only be used for debugging purposes.
    /// </remarks>
    ///
    public static string GetLockDebuggerDisplay(object lockObject)
	{
        string lockObjectLabel = lockObject.GetType().Name;
        if (Monitor.TryEnter(lockObject))
		{
            Monitor.Exit(lockObject);

#if false
			// <lockObject> is not locked by another thread -- see if it's locked by this
			// thread, by creating another thread and attempting to lock <lockObject>
			bool isLocked = false;
			Thread thread = new Thread(delegate()
			{
				if (Monitor.TryEnter(lockObject))
					Monitor.Exit(lockObject);
				else
					isLocked = true;
			});
			thread.Start();
			thread.Join();
			if (isLocked)
				return String.Format("{0} - Locked by this thread", lockObjectLabel);
			else
				return String.Format("{0} - Not locked", lockObjectLabel);
#else
            return String.Format("{0} - Not locked by another thread", lockObjectLabel);
#endif
		}
		else
			return String.Format("{0} - Locked by another thread", lockObjectLabel);
    }

    /// <summary>
    /// Removes the last character of a string, if that character is a newline character.
    /// </summary>
    ///
    /// <param name="text">The input string.</param>
    ///
    public static string DeleteTrailingNewline(string text)
    {
        if (text.EndsWith("\n"))
            return text.Substring(0, text.Length - 1);
        else
            return text;
    }

    /// <summary>
    /// Compares two specified <n>Double</n> values and returns an integer that indicates their
    /// relative position in the sort order. 
    /// </summary>
    ///
    /// <param name="x">The first <n>Double</n> value</param>
	///
    /// <param name="y">The second <n>Double</n> value</param>
	///
    /// <returns>
    /// 	<list type="table">
    /// 		<listheader>
    /// 			<term>Return value</term>
    /// 			<description>Condition</description>
    /// 		</listheader>
    /// 		<item>
    /// 			<term>Less than zero</term>
    /// 			<description><pr>x</pr> is less than <pr>y</pr></description>
    /// 		</item>
    /// 		<item>
    /// 			<term>Zero</term>
    /// 			<description><pr>x</pr> is equal to <pr>y</pr></description>
    /// 		</item>
    /// 		<item>
    /// 			<term>Greater than zero</term>
    /// 			<description><pr>x</pr> is greater than <pr>y</pr></description>
    /// 		</item>
    /// 	</list>
    /// </returns>
	///
    public static int Compare(double x, double y)
    {
        if (x == y)
            return 0;
        else
        if (x < y)
            return -1;
        else
            return 1;
    }

    /// <summary>
    /// Performs a binary search of a sorted "virtual array".
    /// </summary>
    ///
    /// <typeparam name="T">The type of items in the "virtual array".</typeparam>
    ///
    /// <param name="itemCount">The number of items in the "virtual array".</param>
    ///
    /// <param name="valueToFind">The value to find.</param>
    ///
    /// <param name="compareItems">A function that compares two values, and returns 0 if they are
    /// 	equal, -1 if the first is less than the second, 1 otherwise.</param>
    ///
    /// <param name="getItem">A function that returns the value of "virtual array" item at a given
    /// 	index.</param>
    ///
    /// <returns>
    /// The index of the last item whose value is less than or equal to <pr>valueToFind</pr>, or -1
    /// if <pr>valueToFind</pr> is less than the value at the beginning of the "virtual array"
    /// or the "virtual array" is empty.
    /// </returns>
    ///
    public static int BinarySearch<T>(int itemCount, T valueToFind, Func<T, T, int> compareItems,
        Func<int, T> getItem)
    {
        // the code below maintains this invariant: we know <valueToFind> is within the range of
        // <rangeLength> items -- i.e. is greater than or equal to the item at index <rangeStart>
        // but less than the item at index (rangeStart + rangeLength)** -- and that range contains
        // at least one item; so, return -1 if that invariant isn't true at the beginning (either
        // because there are no items, or because <valueToFind> is less than the value at the
        // start of the collection), otherwise initialize the range to encompass the entire
        // collection; **for the purpose of this algorithm, the item at index <itemCount> has a
        // value of infinity
        if ((itemCount == 0) || (compareItems(valueToFind, getItem(0)) < 0))
            return -1;
        int rangeStart = 0;
        int rangeLength = itemCount;

        // binary-search until we've reduced the range to one item
        while (rangeLength > 1)
        {
            int leftHalfLength = rangeLength / 2;
            T lowestValueInRightHalf = getItem(rangeStart + leftHalfLength);
            int result = compareItems(valueToFind, lowestValueInRightHalf);
            if (result < 0)
                rangeLength = leftHalfLength; // item is in left half of range (if anywhere)
            else
            {
                rangeStart += leftHalfLength; // item is in right half of range (if anywhere)
                rangeLength -= leftHalfLength;
            }
        }

        // <valueToFind> is between <rangeStart> (inclusive) and the item after that (exclusive)
        return rangeStart;
    }
}

#if !SILVERLIGHT
/// <summary>
/// Indicates an error that occurred within <c>DnUtil.LoadAssembly</c>.
/// </summary>
///
public class LoadAssemblyException : Exception
{
    /// <summary>
    /// Creates an instance of this exception class.
    /// </summary>
    ///
    /// <param name="assemblyName">The name of the assembly that was trying to be loaded.
    ///     </param>
    ///
    /// <param name="innerException">The inner exception.</param>
    ///
    internal LoadAssemblyException(string assemblyName, Exception innerException) :
        base(String.Format(CommonResources.FailedToLoadAssembly, assemblyName,
			innerException.Message), innerException)
	{
	}
}
#endif

/// <summary>
/// Indicates an error that occurred within <r>Util.CreateInstance</r>.
/// </summary>
///
public class CreateInstanceException : Exception
{
	/// <summary>
	/// Creates an instance of this exception class, given an inner exception.
	/// </summary>
	///
	/// <param name="assemblyName">The name of the assembly that was trying to be loaded.
	///     </param>
	///
	/// <param name="typeName">The name of the type that was trying to be created.</param>
	///
	/// <param name="innerException">The inner exception.</param>
	///
	internal CreateInstanceException(string assemblyName, string typeName,
			Exception innerException) :
		this(assemblyName, typeName, innerException, innerException.Message)
	{
	}

	/// <summary>
	/// Creates an instance of this exception class, given an inner exception message.
	/// </summary>
	///
	/// <param name="assemblyName">The name of the assembly that was trying to be loaded.
	///     </param>
	///
	/// <param name="typeName">The name of the type that was trying to be created.</param>
	///
	/// <param name="innerException">The inner exception.</param>
	///
	/// <param name="additionalMessage">Message text to append to the exception message.
	///     </param>
	///
	internal CreateInstanceException(string assemblyName, string typeName,
			Exception innerException, string additionalMessage) :
		base(String.Format(CommonResources.FailedToCreateInstance, typeName, assemblyName,
			additionalMessage), innerException)
	{
	}

    /// <summary>
    /// Creates an instance of this exception class, given only an exception message.
    /// </summary>
    ///
    /// <param name="message">The exception message</param>
    ///
    internal CreateInstanceException(string message) :
        base(message)
    {
    }
}

/// <summary>
/// Indicates an internal error, i.e. a situation that wasn't expected to be possible.
/// </summary>
///
public class InternalErrorException : Exception
{
    /// <summary>
    /// Creates an instance of this exception class.
    /// </summary>
    ///
    /// <param name="errorCode">A code which (uniquely, ideally) identifies the internal error.
    ///     </param>
    ///
    public InternalErrorException(string errorCode) :
        base(String.Format(CommonResources.InternalError, errorCode))
	{
	}
}

/// <summary>
/// This utility class implements a stack of disposable objects, intended for
/// use within a "using" statement.
/// </summary>
///
/// <remarks>
/// When Disposer's IDisposable.Dispose method is called (either explicitly,
/// or implicitly by a "using" statement), the object references that were
/// pushed onto the Disposer stack are disposed of in the reverse order in
/// which they were pushed on.
/// </remarks>
///
/// <example>
/// The following example causes a <c>Font</c> and a <c>FileStream</c> object
/// to be disposed at the bottom of the "using" block.
/// <code>
/// using (Disposer disposer = new Disposer())
/// {
///     ...
///     Font font = new Font("Arial", 10.0f);
///     disposer.Push(font);
///     ...
///     FileStream fs = new FileStream(...);
///     disposer.Push(fs);
///     ...
/// } // at this point, IDisposable.Dispose is called on fs, then on font
/// </code>
/// </example>
///
public class Disposer : IDisposable
{
	/// <summary>
	/// Stack of objects to dispose.
	/// </summary>
	///
	private Stack<IDisposable> _stack = new Stack<IDisposable>();

	/// <summary>
	/// Adds an object to the top of the stack of objects to dispose.
	/// </summary>
    /// 
    /// <param name="d">The value to push onto the stack.</param>
	///
	public void Push(IDisposable d)
	{
		// implement Push() instead of inheriting from Stack to check that
		// <d> implements IDisposable at the time Push() is called
		if (d != null)
			_stack.Push(d);
	}

    /// <summary>
    /// Disposes of all objects that were pushed onto the stack.
    /// </summary>
    ///
	public void Dispose()
	{
		while (_stack.Count > 0)
		{
			IDisposable d = (IDisposable) _stack.Pop();
			d.Dispose();
		}
	}
}

#if !SILVERLIGHT
/// <summary>
/// Implements <c>WaitHandle</c> functionality, allowing a value of a specified
/// type to be passed to <c>Set</c> for subsequent retrieval by the caller of
/// <c>WaitOne</c>.
/// </summary>
///
/// <typeparam name="T">The type of the value passed to <c>Set</c>.</typeparam>
///
public class EventWithValue<T> : IDisposable
{
	ManualResetEvent _event;
	T _value;

	/// <summary>
	/// Initializes a new instance of the <c>EventWithValue</c> class.
    /// The event is initially reset.
	/// </summary>
	///
	public EventWithValue()
	{
		_event = new ManualResetEvent(false);
	}

	/// <summary>
	/// Triggers <c>WaitOne</c> to unblock by a call to <c>Set</c> (on another
	/// thread, typically).
	/// </summary>
	///
	/// <param name="value">The value to return from <c>WaitOne</c>.</param>
	///
	public void Set(T value)
	{
		_value = value;
		_event.Set();
	}

	/// <summary>
	/// Blocks until <c>Set</c> is called (on another thread, typically).
	/// </summary>
	///
	/// <param name="timeout">After this many milliseconds, <c>WaitOne</c>
	/// 	times out and returns.</param>
	///
	/// <param name="timedOut">Returns true if a timeout occurred false if not.
	/// 	</param>
	///
	/// <returns>
	/// The value passed to <c>Set</c>.  On timeout, the default value of
	/// <c>T</c> is returned.
	/// </returns>
	///
	public T WaitOne(int timeout, out bool timedOut)
	{
		timedOut = !_event.WaitOne(timeout, false);
		return _value;
	}

	void IDisposable.Dispose()
	{
		if (_event != null)
			_event.Close();
	}
}
#endif

#if !SILVERLIGHT
/// <summary>
/// Enumerates arguments within a command line.
/// </summary>
///
[DebuggerDisplay("{DebugDisplay}")]
public class ArgumentEnumerator
{
	/// <summary>
	/// Argument enumerator.
	/// </summary>
	IEnumerator<string> _argEnum;

	/// <summary>
	/// Indicates if we've reached the end of the arguments.  In this case, <c>Current</c> is
	/// invalid.
	/// </summary>
	bool _atEnd;

#if DEBUG
	/// <summary>
	/// Indicates that the first call to <c>MoveNext</c> was made.  For debugging purposes only.
	/// </summary>
	bool _started;

    /// <summary>
    /// Number of arguments.  For debugging purposes only.
    /// </summary>
    int ArgCount;

    /// <summary>
    /// Arguments in a single string.  For debugging purposes only.
    /// </summary>
    string ArgString;
#endif

	/// <summary>
	/// Initializes an instance of the <c>Arguments</c> class given a string enumerator (for
	/// example, the array of arguments passed into an application's <n>Main</n> entry point).
	/// </summary>
	///
	/// <param name="arguments">Command-line arguments.  This may be a string array,
	/// 	a List&lt;string&gt;, or any other object that implements
	/// 	IEnumerable&lt;string&gt;.</param>
	///
	/// <remarks>
	/// The first call to <c>MoveNext</c> or <c>GetNext</c> (or a similar method) advances to the
	/// first argument.
	/// </remarks>
	///
	public ArgumentEnumerator(IEnumerable<string> arguments)
	{
#if DEBUG
        // set <ArgCount> and <ArgString> (for debugging purposes)
        ArgCount = 0;
        StringBuilder strb = new StringBuilder(200);
        foreach (string arg in arguments)
        {
            ArgCount++;
            if (strb.Length > 0)
                strb.Append(" ");
            if ((arg.IndexOf(' ') >= 0) || (arg.IndexOf('"') >= 0))
                strb.AppendFormat("\"{0}\"", arg.Replace("\"", "\"\""));
            else
                strb.Append(arg);
        }
		ArgString = strb.ToString();
#endif
		_argEnum = arguments.GetEnumerator();
	}

	/// <summary>
	/// Initializes an instance of the <c>Arguments</c> class given a string containing arguments.
	/// </summary>
	///
    /// <param name="argumentString">The string of command-line arguments.</param>
	///
    /// <remarks>
	/// <para>
	/// The structure of command-line arguments mirrors the Windows command lines.  Arguments are
	/// separated by spaces.  Use double quotes to include spaces within an argument.  Use a pair
	/// of double quotes within a double-quoted argument to represent a double quote.
	/// </para>
	/// <para>
	/// The first call to <c>MoveNext</c> or <c>GetNext</c> (or a similar method) advances to the
	/// first argument.
	/// </para>
    /// </remarks>
	///
	public ArgumentEnumerator(string argumentString)
		: this(ParseArguments(argumentString))
	{
	}

	/// <summary>
	/// Returns the current argument as a string.
	/// </summary>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was at the end of the argument list when this method was called.
	/// </exception>
	///
	public string Current
	{
		get
		{
			if (_atEnd)
				throw new UsageException();
			return _argEnum.Current;
		}
	}

    /// <summary>
    /// Returns the current argument as an <n>Int32</n> value.
    /// </summary>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was at the end of the argument list when this method was called,
	/// </exception>
	///
	/// <exception cref="SpecificUsageException">
	/// The argument isn't a valid <n>Int32</n> value.
	/// </exception>
	///
    public int CurrentAsInt32
    {
		get
		{
            int result;
            if (!int.TryParse(Current, out result))
            {
                throw new SpecificUsageException("Command line error: Expected an integer, got \"{0}\"",
                    Current);
//TODO: move above to resource
            }
            else
                return result;
		}
    }

	/// <summary>
	/// Returns the current argument as a member of an enumeration.
	/// </summary>
	///
	/// <typeparam name="T">The type of the enumeration</typeparam>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was at the end of the argument list when this method was called.
	/// </exception>
	///
	/// <exception cref="SpecificUsageException">
	/// The argument isn't a valid member of enumeration <tpr>T</tpr>.
	/// </exception>
	///
    public T GetCurrentAsEnum<T>()
    {
        try
        {
            return (T)Enum.Parse(typeof(T), Current, true);
        }
        catch (ArgumentException)
        {
#if SILVERLIGHT
            throw new UsageException();
#else
			throw new SpecificUsageException(
                "Command line error: For argument \"{0}\", one of the following was expected: {1}",
                Current, String.Join(", ", Enum.GetNames(typeof(T))));
//TODO: move above to resource
#endif
        }
       
    }

	/// <summary>
	/// Advances to the next argument.
	/// </summary>
	///
	/// <returns>
	/// True if there is an argument, false if there are no more arguments.
	/// </returns>
	///
	/// <remarks>
	/// This method doesn't throw an exception when the end of the argument list is reached, but
	/// subsequent calls to other properties and methods (such as <c>Current</c> and
	/// <c>CurrentIsOption</c>) will throw a <c>UsageException</c> at that point.
	/// </remarks>
	///
	public bool MoveNext()
	{
		if (_atEnd)
			return false;
#if DEBUG
		_started = true;
#endif
		_atEnd = !_argEnum.MoveNext();
		return !_atEnd;
	}

	/// <summary>
	/// Advances to the next argument and returns its string value.
	/// </summary>
	///
	/// <returns>
	/// The string value of the next argument.
	/// </returns>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was at the end of the argument list when this method was called.
	/// </exception>
	///
	public string GetNext()
	{
		if (!MoveNext())
			throw new UsageException();
		return Current;
	}

	/// <summary>
	/// Returns true if the current argument is an option that's preceded with a forward slash (/)
	/// or hyphen (-).
	/// </summary>
	///
	/// <remarks>
	/// If the end of the argument list has been reached (i.e. there is no current argument),
	/// <c>UsageException</c> is thrown.
	/// </remarks>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was at the end of the argument list when this method was called.
	/// </exception>
	///
	public bool CurrentIsOption()
	{
		if (_atEnd)
			throw new UsageException();
		return Current.StartsWith("/") || Current.StartsWith("-");
	}

	/// <summary>
	/// Returns <n>true</n> if the current argument is a given option that's preceded with a
	/// forward slash (/) or hyphen (-).  The comparison is case-insensitive.
	/// </summary>
	///
	/// <param name="name">The name of the option, without the preceding forward slash character.
	/// 	</param>
	///
	/// <exception cref="ArgumentException">
	/// <pr>name</pr> starts with "/".
	/// </exception>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was at the end of the argument list when this method was called.
	/// </exception>
	///
	public bool CurrentIsOption(string name)
	{
        if (name.StartsWith("/") || name.StartsWith("-"))
		{
            throw new ArgumentException(
				CommonResources.ArgumentEnumerator_LeadingSlashOrHyphen, "name");
		}
        else
		if (_atEnd)
			throw new UsageException();
		return (String.CompareOrdinal(Current, "/" + name) == 0) ||
		       (String.CompareOrdinal(Current, "-" + name) == 0);
	}

	/// <summary>
	/// Throws <c>UsageException</c> if there are any more arguments in the argument list.
	/// </summary>
	///
	/// <remarks>
	/// This method advances to the next argument, if any.
	/// </remarks>
	///
	/// <exception cref="UsageException">
	/// The argument enumerator was not at the end of the argument list when this method was
	/// called.
	/// </exception>
	///
	public void NoMoreArgumentsAllowed()
	{
		if (MoveNext())
			throw new UsageException();
	}

    /// <summary>
    /// Parses a string containing command-line arguments.
    /// </summary>
    ///
    /// <param name="stringToParse">The string of command-line arguments to parse.</param>
	///
    /// <returns>
    /// A parsed collection of arguments.
    /// </returns>
    /// 
    /// <remarks>
	/// The structure of command-line arguments mirrors the Windows command lines.  Arguments are
	/// separated by spaces.  Use double quotes to include spaces within an argument.  Use a pair
	/// of double quotes within a double-quoted argument to represent a double quote.
    /// </remarks>
	///
    public static ReadOnlyCollection<string> ParseArguments(string stringToParse)
    {
        // /Foo  ""x"" "" "abc" de"f g"hi "jkl""mno"
        //TODO: move test into DnUtil_Test

		// initialize <charEnum> to enumerate through the characters in <stringToParse>
        CharEnumerator charEnum = stringToParse.GetEnumerator();

		// arguments will be accumulated into <arg>
        List<string> args = new List<string>(10);

		// as we parse <stringToParse>, the current argument will be accumulated into <currentArg>
        StringBuilder currentArg = new StringBuilder(stringToParse.Length / 2);

		// <inArg> is true while we're inside an argument
        bool inArg = false;

		// <inQuotes> is true while we're inside double quotes
        bool inQuotes = false;

		// advance to the first character; quit if none
		if (!charEnum.MoveNext())
			return new ReadOnlyCollection<string>(args);
		char ch = charEnum.Current;

		// the code below needs to have access to the current character <ch> and the next character
		// <chNext>, so get <chNext> -- set it to char.MinValue if we reached the end of the line
		char chNext;
		if (!charEnum.MoveNext())
			chNext = char.MinValue;
		else
			chNext = charEnum.Current;

		// parse the string
        while (true)
        {
			// interpret the current character
            if (inQuotes)
            {
				// we're currently within double quotes
				if (ch == char.MinValue)
				{
					// end-of-line ends the current argument
                    args.Add(currentArg.ToString());
                }
				else
				if (ch == '"')
				{
					// double quotes ends quoting mode, unless there are two in a row,
					// in which case a double quote is appended to the current argument
					if (chNext == '"')
					{
						// we encountered a pair of adjacent double quotes within a quoted
						// argument -- append a double quote to the current argument and then
						// advance <ch> and <chNext> so the second double quote will be skipped
						currentArg.Append('"');
						ch = chNext;
						if (!charEnum.MoveNext())
							chNext = char.MinValue;
						else
							chNext = charEnum.Current;
					}
					else
					{
						// end quoting mode
						inQuotes = false;
					}
				}
				else
				{
					// continue the current argument
					currentArg.Append(ch);
				}
            }
            else
            {
                // we're not within double quotes currently
                bool isWhiteSpace = Char.IsWhiteSpace(ch);
                if (inArg && ((ch == char.MinValue) || isWhiteSpace))
                {
                    // end-of-line or white space within an argument ends the current argument
                    args.Add(currentArg.ToString());
                    currentArg.Length = 0;
                    inArg = false;
                }
                else
                if (ch == '"')
                {
                    // begin quoting mode; also, if we weren't within an argument, we are now
                    inQuotes = true;
                    inArg = true; // if we weren't in an argument before, we are now
                }
				else
                if (isWhiteSpace)
                {
                    // white space between arguments is ignored
                }
                else
				{
					// begin a new argument, or continue the current argument
					currentArg.Append(ch);
					inArg = true; // if we weren't in an argument before, we are now
				}
            }

            // quit if we reached the end of the command line
            if (ch == char.MinValue)
                break;

			// advance <ch> and <chNext> one character position within the string
			ch = chNext;
			if (!charEnum.MoveNext())
				chNext = char.MinValue;
			else
				chNext = charEnum.Current;
        }

        // done -- return the arguments
        return new ReadOnlyCollection<string>(args);
    }

#if DEBUG
	/// <summary>
	/// The string displayed in the debugger.
	/// </summary>
	string DebugDisplay
    {
        get
        {
			StringBuilder output = new StringBuilder(100);
			output.AppendFormat("{0} argument(s); ", ArgCount);
			if (!_started)
				output.Append("before start of arguments");
			else
			if (_atEnd)
				output.Append("at end of arguments");
			else
				output.AppendFormat("current is: {0}", Current);
			return output.ToString();
        }
    }
#endif
}
#endif

#if !SILVERLIGHT && DEBUG && UNITTESTS
/// <summary>
/// Unit-tests <r>ArgumentEnumerator</r>.
/// </summary>
///
public class ArgumentEnumerator_Test
{
	/// <summary>
	/// Run all <r>ArgumentEnumerator</r> unit tests.
	/// </summary>
	///
	public static void RunAllTests()
	{
        TestParseArguments();
	}

    /// <summary>
    /// Tests <r>ArgumentEnumerator.ParseArguments</r>.
    /// </summary>
    ///
    public static void TestParseArguments()
    {
        // test data, consisting of input and correct output for ArgumentEnumerator.ParseArguments
        ParseArgumentsTest[] tests = new ParseArgumentsTest[]
        {
            new ParseArgumentsTest(
                "/Foo  \"\"x\"\" \"\" \"abc\" de\"f g\"hi \"jkl\"\"mno\"",
                new string[]
                {
                    "/Foo", "x", "", "abc", "def ghi", "jkl\"mno"
                }
            ),
            new ParseArgumentsTest(
                "\"",
                new string[]
                {
                    ""
                }
            ),
            new ParseArgumentsTest(
                "",
                new string[]
                {
                }
            ),
        };

        // execute ArgumentEnumerator.ParseArguments for each test in <tests>
        foreach (ParseArgumentsTest test in tests)
        {
            ReadOnlyCollection<string> args = ArgumentEnumerator.ParseArguments(test.StringToTest);
            Test.FailIfNotEqual(args.Count, test.CorrectAnswer.Length);
            for (int i = 0; i < args.Count; i++)
                Test.FailIfNotEqual(args[i], test.CorrectAnswer[i]);
        }
    }

    /// <summary>
    /// Helper class used by <r>ArgumentEnumerator_Test.TestParseArguments</r>.
    /// </summary>
    class ParseArgumentsTest
    {
        public string StringToTest;
        public string[] CorrectAnswer;
        public ParseArgumentsTest(string stringToTest, string[] correctAnswer)
        {
            StringToTest = stringToTest;
            CorrectAnswer = correctAnswer;
        }
    }
}
#endif

#if !SILVERLIGHT
/// <summary>
/// Exception indicating incorrect command-line usage.  The application should display command-line
/// usage information.
/// </summary>
///
public class UsageException : Exception
{
	/// <summary>
	/// Initializes an instance of this exception class.
	/// </summary>
	/// 
    public UsageException()
    {
    }

	/// <summary>
	/// Initializes an instance of this exception class, specifying an error message.
	/// </summary>
    /// 
    /// <param name="message">The error message.</param>
	/// 
    protected UsageException(string message)
        : base(message)
    {
    }
}
#endif

#if !SILVERLIGHT
/// <summary>
/// Exception indicating incorrect command-line usage.  The application should display
/// <r>UsageException</r>.<n>Message</n>.
/// </summary>
///
public class SpecificUsageException : UsageException
{
	/// <summary>
	/// Initializes an instance of this exception class by formatting an error string.
	/// </summary>
	/// 
	/// <param name="format">The error message format string.  If <pr>args</pr> is empty,
	/// 	<pr>format</pr> is used without formatting.</param>
	///
	/// <param name="args">Formatting arguments.</param>
	///
	public SpecificUsageException(string format, params object[] args)
		: base((args.Length == 0) ? format :
			String.Format(CultureInfo.InvariantCulture, format, args))
	{
	}
}
#endif

/// <summary>
/// Represents a boolean whose value can be exchanged with another value as
/// an atomic operation.
/// </summary>
///
/// <remarks>
/// This struct exists to overcome the limitation that
/// <c>Interlocked.Exchange</c> does not operate on <c>bool</c> values.
/// You can use <c>AtomicBool</c>c> the same way you would use a <c>bool</c>,
/// but <c>AtomicBool</c> has an <c>Exchange</c> method that's analagous to
/// <c>Interlocked.Exchange</c>.
/// </remarks>
///
/// <example>
/// The following example shows various ways of using <c>AtomicBool</c>.
/// <code>
/// AtomicBool b = true;
/// ...
/// if (b)
/// {
///     // b is true
///     ...
/// }
/// ...
/// if (!b.Exchange(true))
/// {
///     // b was false, and we just set it to true
///     ...
/// }
/// </code>
/// </example>
///
[DebuggerDisplay("{Value}")]
public struct AtomicBool
{
    ///////////////////////////////////////////////////////////////////////////////////////////////
	// Private Fields
	//

	/// <summary>
	/// Holds the value of the <c>Value</c> property, represented as an int (1 for true, 0 for
	/// false) so that <c>Interlocked.Exchange</c> can operate on it.
	/// </summary>
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
	int _value;

    ///////////////////////////////////////////////////////////////////////////////////////////////
	// Public Properties
	//

	/// <summary>
	/// Gets or sets the <c>bool</c> value of this <c>AtomicBool</c>.
	/// </summary>
	///
	public bool Value
	{
		get
		{
			return ToBool(_value);
		}
		set
		{
			_value = ToInt(value);
		}
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////
	// Public Methods
	//

	/// <summary>
	/// Initializes this <c>AtomicBool</c> value to a given <c>bool</c> value.
	/// </summary>
    /// 
    /// <param name="value">The value to initialize to.</param>
	///
	public AtomicBool(bool value)
	{
		_value = ToInt(value);
	}

	/// <summary>
	/// Sets this <c>AtomicBool</c> to a given <c>bool</c> value, and returns the previous
	/// <c>bool</c> value, as an atomic operation.
	/// </summary>
    /// 
    /// <param name="value">The value to set to.</param>
    ///
	public bool Exchange(bool value)
	{
		return ToBool(Interlocked.Exchange(ref _value, ToInt(value)));
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////
	// Public Conversions
	//

	/// <summary>
	/// Converts an <c>AtomicBool</c> value to a <c>bool</c>.
	/// </summary>
    /// 
    /// <param name="atomicBool">The value to convert.</param>
    ///
	public static implicit operator bool(AtomicBool atomicBool)
	{
		return atomicBool.Value;
	}

	/// <summary>
	/// Converts a <c>bool</c> value to an <c>AtomicBool</c>.
	/// </summary>
    /// 
    /// <param name="value">The value to convert.</param>
    ///
	public static implicit operator AtomicBool(bool value)
	{
		return new AtomicBool(value);
	}

    ///////////////////////////////////////////////////////////////////////////////////////////////
	// Private Methods
	//

	/// <summary>
	/// Converts an <c>int</c> value that represents a bool (1 for true, 0 for false) to the
	/// corresponding <c>bool</c> value.
	/// </summary>
	///
	static bool ToBool(int value)
	{
		return (value != 0);
	}

	/// <summary>
	/// Converts a <c>bool</c> value to an <c>int</c> value that represents that represents the
	/// bool (1 for true, 0 for false).
	/// </summary>
	///
	static int ToInt(bool value)
	{
		return (value ? 1 : 0);
	}
}

#if false
/// <summary>
/// The base class for <r>FatalException</r> and <r>NonfatalException</r> exceptions.
/// </summary>
///
public abstract class AnticipatedException : Exception
{
    /// <summary>
    /// Initializes an instance of this exception class.
    /// </summary>
    ///
    /// <param name="message">The exception message.</param>
    ///
    protected AnticipatedException(string message) :
        base(message)
    {
    }
}
#endif

/// <summary>
/// Indicates a general application error that needs to be reported to the user (e.g. through the
/// UI for a client application, or in the event log for a service application).  The application
/// can continue to run.
/// </summary>
///
public class NonfatalException : /*Anticipated*/Exception
{
    /// <summary>
    /// Initializes an instance of this exception class.
    /// </summary>
    /// 
    public NonfatalException()
    {
    }

	/// <summary>
	/// Initializes an instance of this exception class.
	/// </summary>
	/// 
	/// <param name="format">The error message format string.  If no <pr>args</pr> are provided,
	/// 	<pr>format</pr> is used as-is, without formatting.</param>
	///
	/// <param name="args">Formatting arguments.</param>
	///
	public NonfatalException(string format, params object[] args)
		: base((args.Length == 0) ? format :
			String.Format(CultureInfo.InvariantCulture, format, args))
	{
	}
}

/// <summary>
/// Indicates a general application error that requires the application to stop.
/// </summary>
///
public class FatalException : /*Anticipated*/Exception
{
	/// <summary>
	/// Initializes an instance of this exception class.
	/// </summary>
	/// 
    /// <param name="format">The error message format string.  If no <pr>args</pr> are provided,
    /// 	<pr>format</pr> is used as-is, without formatting.</param>
	///
	/// <param name="args">Formatting arguments.</param>
	///
	public FatalException(string format, params object[] args)
        : base((args.Length == 0) ? format :
			String.Format(CultureInfo.InvariantCulture, format, args))
	{
	}

    /// <summary>
    /// Initializes an instance of this exception class.
    /// </summary>
    /// 
    /// <param name="innerException">The inner exception, or <n>null</n>if none.</param>
    ///
    /// <param name="format">The error message format string.  If no <pr>args</pr> are provided,
    /// 	<pr>format</pr> is used as-is, without formatting.</param>
    ///
    /// <param name="args">Formatting arguments.</param>
    ///
    public FatalException(Exception innerException, string format, params object[] args)
        : base((args.Length == 0) ? format :
            String.Format(CultureInfo.InvariantCulture, format, args), innerException)
    {
    }
}

/// <summary>
/// Encapsulates a string.  An instance of this class may be returned from a method used within a
/// "[DebuggerDisplay]" attribute to display a string without surrounding quotes.
/// </summary>
///
public class EncapsulatedString
{
    /// <summary>
    /// The encapsulated string.
    /// </summary>
    string _value;

    /// <summary>
    /// Initializes an instance of this class by formatting a string.
    /// </summary>
    ///
	/// <param name="format">The format string to use.  If <pr>args</pr> is zero-length,
	/// 	<pr>format</pr> is used as-is, without formatting.</param>
	///
	/// <param name="args">Arguments for format string.</param>
	///
    public EncapsulatedString(string format, params object[] args)
    {
        _value = Util.Format(format, args);
    }

	/// <summary>
	/// Returns the encapsulated string.
	/// </summary>
	///
    public override string ToString()
    {
        return _value;
    }
}

/// <summary>
/// A byte array which can be appended to and which will grow as needed.
/// </summary>
///
[DebuggerDisplay("{DebuggerDisplay}")]
public class GrowableBuffer
{
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    /// <summary>
    /// The buffer.  The first <r>_length</r> bytes contain data from the application; the
	/// remainder are not yet in use.
    /// </summary>
    byte[] _buffer;

    /// <summary>
    /// The number of bytes of <r>_buffer</r> that are currently in use.
    /// </summary>
    int _length;

    /// <summary>
    /// If the buffer runs out of space, it grows by this factor.
    /// </summary>
    double _growBy;

    /// <summary>
    /// The maximum size of a buffer, in bytes.
    /// </summary>
    const int MaxSize = int.MaxValue / 4;

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    /// <summary>
    /// Returns an <n>ArraySegment</n> containing the contents of the buffer.  Note that the
    /// <n>Contents</n> field of the returned <n>ArraySegment</n> is guaranteed to be zero.
    /// </summary>
    public ArraySegment<byte> Contents
    {
        get
        {
            return new ArraySegment<byte>(_buffer, 0, _length);
        }
    }

    /// <summary>
    /// The number of bytes of data in the buffer.  Does not include unused buffer space.
    /// </summary>
    public int Length
    {
        get
        {
            return _length;
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    /// <summary>
    /// Initializes an instance of this class.
    /// </summary>
    ///
    /// <param name="initialSize">The initial size to allocate the buffer, in bytes.  Must be
	/// 	greater than zero.</param>
    ///
    /// <param name="growBy">If the buffer runs out of space, it grows by this factor.  Must be
    ///     greater than 1.0.</param>
    ///
    public GrowableBuffer(int initialSize, double growBy)
    {
        // check parameters
        if (initialSize <= 0)
            throw new ArgumentException("initialSize must be greater than zero", "initialSize");
        if (growBy <= 1)
            throw new ArgumentException("growBy must be greater than 1.0", "growBy");

        // save state
        _growBy = growBy;

        // allocate the buffer
        _buffer = new byte[initialSize];
    }

    /// <summary>
    /// Initializes an instance of this class, providing an existing buffer to use.
    /// </summary>
    ///
    /// <param name="buffer">The buffer to use.  The new <r>GrowableBuffer</r> instance will take
    ///     ownership of this buffer -- the caller should no longer modify it.</param>
    ///
    /// <param name="growBy">If the buffer runs out of space, it grows by this factor.  Must be
    ///     greater than 1.0.</param>
    ///
    public GrowableBuffer(byte[] buffer, double growBy)
    {
        // check parameters
        if (growBy <= 1)
            throw new ArgumentException("growBy must be greater than 1.0", "growBy");

        // save state
        _growBy = growBy;

        // save the buffer
        _buffer = buffer;
        _length = buffer.Length;
    }

    /// <summary>
    /// Appends a range of bytes to this buffer.
    /// </summary>
    ///
    /// <param name="source">The source of bytes to copy to this buffer.</param>
    ///
    /// <param name="offset">The offset within <pr>source</pr> at which to start copying.</param>
    ///
    /// <param name="count">The number of bytes to copy.</param>
    ///
    public void AppendBytes(byte[] source, int offset, int count)
    {
        // grow the buffer if needed to accommodate <count> more bytes
        EnsureAvailableByteCount(count);

        // append source bytes to <_buffer>
        Buffer.BlockCopy(source, offset, _buffer, _length, count);
        _length += count;
    }

    /// <summary>
    /// Performs UTF-8 encoding on a string and appends the result to this buffer.
    /// </summary>
    ///
    /// <param name="text">The text to append to this buffer.</param>
    ///
    public void AppendUtf8(string text)
    {
        EnsureAvailableByteCount(Encoding.UTF8.GetMaxByteCount(text.Length));
        _length += Encoding.UTF8.GetBytes(text, 0, text.Length, _buffer, _length);
    }

    /// <summary>
    /// Deletes a range of bytes within the buffer.  Bytes following this range are shifted toward
    /// the beginning of the buffer.
    /// </summary>
    ///
    /// <param name="offset">The offset of the reange of bytes to delete.</param>
    ///
    /// <param name="size">The number of bytes to delete.</param>
    ///
    public void DeleteBytes(int offset, int size)
    {
        // check arguments; set <tailOffset> to the offset of the bytes following the range that's
        // to be deleted; set <tailLength> to the number of bytes at offset <tailOffset>
        if (offset > _length)
            throw new ArgumentException("offset exceeds Length", "offset");
        int tailOffset = offset + size;
        int tailLength = _length - tailOffset;
        if (tailLength < 0)
        {
            throw new ArgumentException("Not that many bytes in buffer at the given offset",
                "size");
        }

        // shift bytes following the given byte range toward the beginning of the buffer
        if (tailLength > 0)
            Buffer.BlockCopy(_buffer, tailOffset, _buffer, offset, tailLength);

        // update state
        _length -= size;
    }

    /// <summary>
    /// Discards the contents of the buffer.  The buffer memory is not deallocated -- it will be
    /// used by subsequent <r>AppendBytes</r> operations.
    /// </summary>
    ///
    public void Clear()
    {
        _length = 0;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Private Properties
    //

#if DEBUG
    /// <summary>
    /// Returns the string used by the "[DebuggerDisplay]" attribute.
    /// </summary>
    ///
    object DebuggerDisplay
    {
        get
        {
            int previewLength = Math.Min(100, _length);
#if SILVERLIGHT
            string preview = Encoding.UTF8.GetString(_buffer, 0, previewLength);
#else
            string preview = Encoding.ASCII.GetString(_buffer, 0, previewLength);
#endif
            if (previewLength < _length)
                preview += "...";
            return new EncapsulatedString("GrowableBuffer - {0} bytes: {1}", _length, preview);
        }
    }
#endif 

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Private Methods
    //

    /// <summary>
    /// Ensures that a given number of unused bytes are available at the end of this buffer.
    /// </summary>
    ///
    /// <param name="count">The desired number of unused bytes at the end of this buffer.</param>
    ///
    void EnsureAvailableByteCount(int count)
    {
        int bytesNeeded = _length + count;
        int newSize = _buffer.Length;
        while (bytesNeeded > newSize)
        {
            double n = Math.Ceiling(newSize * _growBy);
            if (n > MaxSize)
                throw new OutOfMemoryException();
            newSize = (int)n;
        }
        if (newSize != _buffer.Length)
        {
            var newBuffer = new byte[newSize];
            Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length);
            _buffer = newBuffer;
        }
    }
}

/// <summary>
/// Implements a read-only view onto an <n>IDictionary</n>.  Note that, while the dictionary itself
/// is read-only, it's the application's responsibility to ensure that keys and values are
/// immutable.
/// </summary>
///
/// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
///
/// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
///
public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    /// <summary>
	/// The wrapped dictionary.
    /// </summary>
    IDictionary<TKey, TValue> _dictionary;

    /// <summary>
	/// Holds the value of <r>Empty</r>
    /// </summary>
    static ReadOnlyDictionary<TKey, TValue> _empty;

    /// <summary>
	/// Gets a read-only empty dictionary.
    /// </summary>
    public static ReadOnlyDictionary<TKey, TValue> Empty
	{
		get
		{
			if (_empty != null)
				_empty = new ReadOnlyDictionary<TKey, TValue>(new Dictionary<TKey, TValue>());
            return _empty;
		}
	}

    /// <summary>
    /// Initializes an instance of this class.
    /// </summary>
    ///
    /// <param name="dictionary">The dictionary to wrap.</param>
    ///
    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }

    /// <summary>
    /// Throws <n>InvalidOperationException</n>, because this <n>IDictionary</n> implementation is
    /// read-only.
    /// </summary>
    ///
    /// <param name="key">The key of the element to add.</param>
    ///
    /// <param name="value">The value of the element to add.</param>
    ///
    void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
    {
        throw NewReadOnlyException();
    }

    /// <summary>
    /// Returns <n>true</n> if an element with the given key is in the dictionary.
    /// </summary>
    ///
    /// <param name="key">The key to look for.</param>
    ///
    bool IDictionary<TKey, TValue>.ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    /// <summary>
    /// Gets a collection containing the dictionary's keys.
    /// </summary>
    ///
    ICollection<TKey> IDictionary<TKey, TValue>.Keys
    {
        get
        {
            return _dictionary.Keys;
        }
    }

    /// <summary>
    /// Throws <n>InvalidOperationException</n>, because this <n>IDictionary</n> implementation is
    /// read-only.
    /// </summary>
    ///
    /// <param name="key">The key of the element to remove.</param>
    ///
    bool IDictionary<TKey, TValue>.Remove(TKey key)
    {
        throw NewReadOnlyException();
    }

    /// <summary>
    /// Attempts to retrieve the value associated with a given key.
    /// </summary>
    ///
    /// <param name="key">The key to look for.</param>
    ///
    /// <param name="value">Where to store the value of the key.</param>
    ///
    /// <returns>
    /// <n>true</n> if the key was found, <n>false</n> if not.
    /// </returns>
    ///
    bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value)
    {
        return _dictionary.TryGetValue(key, out value);
    }

    /// <summary>
    /// Gets a collection containing the dictionary's values.
    /// </summary>
    ///
    ICollection<TValue> IDictionary<TKey, TValue>.Values
    {
        get
        {
            return _dictionary.Values;
        }
    }

    /// <summary>
    /// Gets the value associated with a given key.  The set operation throws a
    /// <n>InvalidOperationException</n>, because this <n>IDictionary</n> implementation is
    /// read-only.
    /// </summary>
    ///
    /// <param name="key">The key to look for.</param>
    ///
    TValue IDictionary<TKey, TValue>.this[TKey key]
    {
        get
        {
            return _dictionary[key];
        }
        set
        {
            throw NewReadOnlyException();
        }
    }

    /// <summary>
    /// Throws <n>InvalidOperationException</n>, because this <n>IDictionary</n> implementation is
    /// read-only.
    /// </summary>
    ///
    /// <param name="item">The item to add.</param>
    ///
    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        throw NewReadOnlyException();
    }

    /// <summary>
    /// Throws <n>InvalidOperationException</n>, because this <n>IDictionary</n> implementation is
    /// read-only.
    /// </summary>
    ///
    void ICollection<KeyValuePair<TKey, TValue>>.Clear()
    {
        throw NewReadOnlyException();
    }

    /// <summary>
    /// Returns <n>true</n> if this dictionary contains a given item.
    /// </summary>
    ///
    /// <param name="item">The item to look for.</param>
    ///
    bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
    {
        return _dictionary.Contains(item);
    }

    /// <summary>
    /// Copies the elements of this dictionary to a given array.
    /// </summary>
    ///
    /// <param name="array">The array to copy to.</param>
    ///
    /// <param name="arrayIndex">The index within <pr>array</pr> at which copying begins.</param>
    ///
    void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
    }

    /// <summary>
    /// Gets the number of elements in the dictionary.
    /// </summary>
    ///
    int ICollection<KeyValuePair<TKey, TValue>>.Count
    {
        get
        {
            return _dictionary.Count;
        }
    }

    /// <summary>
    /// Returns <n>true</n>, indicating that this dictionary is read-only.
    /// </summary>
    ///
    bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
    {
        get
        {
            return true;
        }
    }

    /// <summary>
    /// Throws <n>InvalidOperationException</n>, because this <n>IDictionary</n> implementation is
    /// read-only.
    /// </summary>
    ///
    /// <param name="item">The item to remove.</param>
    ///
    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        throw NewReadOnlyException();
    }

    /// <summary>
    /// Returns an enumerator that iterates through the elements in the dictionary.
    /// </summary>
    ///
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    /// <summary>
    /// Returns an enumerator that iterates through the elements in the dictionary.
    /// </summary>
    ///
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    /// <summary>
    /// Returns an <n>InvalidOperationException</n> with a message that indicates that this
    /// dictionary is read-only.
    /// </summary>
    ///
    Exception NewReadOnlyException()
    {
        throw new InvalidOperationException("Dictionary is read-only");
    }
}

/// <summary>
/// TODO
/// </summary>
///
public interface ILogDestination
{
    /// <summary>
    /// TODO
    /// </summary>
    /// <param name="format">TODO</param>
    /// <param name="args">TODO</param>
    ///
    string LogInfo(string format, params object[] args);

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="format">TODO</param>
    ///
    /// <param name="args">TODO</param>
    ///
    string LogWarning(string format, params object[] args);

    /// <summary>
    /// TODO
    /// </summary>
    /// 
    /// <param name="format">TODO</param>
    /// 
    /// <param name="args">TODO</param>
    ///
    string LogError(string format, params object[] args);
};

/// <summary>
/// TODO
/// </summary>
///
[DebuggerDisplay("StringSet: {Count} string(s)")]
public class StringSet : IEnumerable<string>
{
    // can't use HashSet<string> because it's not supported in Silverlight

    /// <summary>
    /// TODO
    /// </summary>
    internal Dictionary<string, bool> _strings;

    /// <summary>
    /// TODO
    /// </summary>
    public int Count
    {
        get
        {
            return _strings.Count;
        }
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    public StringSet()
    {
        _strings = new Dictionary<string, bool>();
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="strings">TODO</param>
    ///
    public StringSet(ICollection<string> strings)
    {
        _strings = new Dictionary<string, bool>(strings.Count);
        foreach (string str in strings)
            Add(str);
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="str">TODO</param>
    ///
    public void Add(string str)
    {
        _strings[str] = true;
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="str">TODO</param>
    ///
    public void Remove(string str)
    {
        _strings.Remove(str);
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    public void Clear()
    {
        _strings.Clear();
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    public String[] ToArray()
    {
        return _strings.Keys.ToArray();
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        foreach (string str in _strings.Keys)
            yield return str;
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        foreach (string str in _strings.Keys)
            yield return str;
    }
}

/// <summary>
/// TODO
/// </summary>
///
public interface IAlertsDisplay
{
    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="alertType">TODO</param>
    ///
    /// <param name="message">TODO</param>
    ///
    void AddMessage(AlertType alertType, string message);
}

/// <summary>
/// TODO
/// </summary>
///
public enum AlertType
{
    /// <summary>
    /// TODO
    /// </summary>
    None,

    /// <summary>
    /// TODO
    /// </summary>
    Information,

    /// <summary>
    /// TODO
    /// </summary>
    Warning
}

// cheaper to allocate than a List<T>, costs only come when you add items to it
/// <summary>
/// TODO
/// </summary>
/// 
/// <typeparam name="T">TODO</typeparam>
///
[DebuggerDisplay("Count = {Count}")]
public class LazyList<T> : IEnumerable<T>
{
    /// <summary>
    /// TODO
    /// </summary>
	List<T> _list;

    /// <summary>
    /// TODO
    /// </summary>
	public List<T> ListOrNull
	{
		get
		{
			return _list;
		}
	}

    /// <summary>
    /// TODO
    /// </summary>
    public int Count
	{
		get
		{
			return (_list != null) ? _list.Count : 0;
		}
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="item">TODO</param>
    ///
	public void Add(T item)
	{
		if (_list == null)
			_list = new List<T>();
		_list.Add(item);
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="index">TODO</param>
    ///
    public void RemoveAt(int index)
    {
        if ((_list == null) || (index >= _list.Count))
            throw new ArgumentOutOfRangeException();
        _list.RemoveAt(index);
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="index">TODO</param>
    ///
    public T this[int index]
    {
        get
        {
            if ((_list == null) || (index >= _list.Count))
                throw new IndexOutOfRangeException();
            return _list[index];
        }
    }

    /// <summary>
    /// TODO
    /// </summary>
    ///
	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return GetEnumerator();
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
	{
		return GetEnumerator();
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    IEnumerator<T> GetEnumerator()
	{
		if (_list == null)
			return new EmptyListEnumerator<T>();
		else
			return _list.GetEnumerator();
	}
}

/// <summary>
/// TODO
/// </summary>
public class LazyStringList : LazyList<string>
{
    /// <summary>
    /// TODO
    /// </summary>
    ///
    /// <param name="format">TODO</param>
    ///
    /// <param name="args">TODO</param>
    ///
    public void Add(string format, params object[] args)
    {
        base.Add(Util.Format(format, args));
    }
}

// returns an enumerator over a list containing zero elements of type T
/// <summary>
/// TODO
/// </summary>
///
/// <typeparam name="T">TODO</typeparam>
///
public class EmptyListEnumerator<T> : IEnumerator<T>
{
    /// <summary>
    /// TODO
    /// </summary>
    ///
	T IEnumerator<T>.Current
	{
		get
		{
			throw NewEmptyListException();
		}
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    void IDisposable.Dispose()
	{
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    object System.Collections.IEnumerator.Current
	{
		get
		{
			throw NewEmptyListException();
		}
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    bool System.Collections.IEnumerator.MoveNext()
	{
		return false;
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    void System.Collections.IEnumerator.Reset()
	{
	}

    /// <summary>
    /// TODO
    /// </summary>
    ///
    Exception NewEmptyListException()
	{
		return new InvalidOperationException("List is empty");
	}
}

/// <summary>
/// The base class for classes that implement simple state machines that typically use the C#
/// "yield" construct to wait for state transitions.
/// </summary>
/// 
/// <remarks>
/// <para>
/// <u>How to implement a state machine</u>
/// </para>
/// <para>
/// A class based on <r>StateMachine</r> is a state machine, implemented by overriding the
/// <r>Implementation</r> method.  <r>Implementation</r> implements an enumeration; each
/// <n>MoveNext</n> call to the enumeration advances the state machine to the next state.
/// Typically, the derived class's <r>Implementation</r> method will contain code such as
/// the following in a number of places:
/// <code>
///     ...begin an asynchronous operation here...
///     yield return true; // wait for async operation to complete
///     ...check the result of the asynchronous operation here...
/// </code>
/// "yield return true" causes the state machine to block.  The asynchronous operation is
/// typically hooked up so that, when it completes, it will call <n>MoveNext</n>, which
/// unblocks the state machine.  (Note that the "true" in "yield return true" has no special
/// meaning; "false" would do the same thing.  "true" is used by convention.)
/// </para>
/// <para>
/// In code like this (above), <s>ResultHolder{}</s> can be used to help implement asynchronous
/// operations in the case where the end of the operation is signalled by a call to a method that
/// has a single parameter of arbitrary type (typically the result of the operation).  The
/// following example (which would be contained within the derived class's <r>Implementation</r>
/// method) assumes that method <n>Foo</n> is defined as having one parameter of type
/// <n>Action&lt;FooResult&gt;</n>.  Calling <n>Foo</n> begins the asynchronous operation; when
/// it completes, the <n>Action</n> (delegate) is called.
/// <code>
///     var foo = new ResultHolder&lt;FooResult&gt;(this);
///     Driver._hardware.Foo(foo.OnDone);
///     yield return true; // wait for async operation to complete
///     ...check the value of foo.Result here...
/// </code>
/// <r>ResultHolder{}</r><c>T</c> implements a method, <r>ResultHolder{}.OnDone</r>, which has a
/// parameter of type <c>T</c>; when that method is called, it in turn calls <n>MoveNext</n>, which
/// unblocks "yield return true".  At that point, the code after "yield return true" can check the
/// value of <s>ResultHolder{}.Result</s>, which contains the value of type <c>T</c>.
/// </para>
/// <para>
/// If a state machine implementation does not make any asynchronous calls at all, it may be
/// implemented as follows: instead of overriding <r>Implementation</r>, override <r>Start</r>.
/// (It would also work to override <r>Implementation</r> and use "yield break;" to exit; that's
/// slightly less efficient.)
/// </para>
/// <para>
/// <u>How to use a state machine</u>
/// </para>
/// <para>
/// Call <r>Start</r> to begin a state machine running; <r>Start</r> will return as soon as the
/// first asynchronous operation within the state machine completes -- at that point, the state
/// machine is running asynchronously.  For state machines with no asynchronous operations,
/// <r>Start</r> will return when the state machine is done.)
/// </para>
/// </remarks>
///
public abstract class StateMachine
{
    IEnumerator<bool> _stateEnumerator;

    /// <summary>
    /// If set to <n>true</n>, then the next time the state machine resumes execution of the next
    /// state transition (due to a call to <r>NextState</r>), the state enumerator will not be
    /// called -- so <r>Implementation</r> will no longer return from "yield return".
    /// </summary>
    public bool IsOrphaned
    {
        get
        {
            return _stateEnumerator == null;
        }
        set
        {
            _stateEnumerator = null;
        }
    }

    /// <summary>
    /// TODO - override if you don't want to use _stateEnumerator, but instead just want a synchronous
    /// action to occur
    /// </summary>
    public virtual void Start()
    {
        _stateEnumerator = Implementation().GetEnumerator();
        NextState();
    }

    // override to implement the state machine

    /// <summary>
    /// TODO
    /// </summary>
    protected virtual IEnumerable<bool> Implementation()
    {
        yield break;
    }

    // called when the state machine exits, e.g. when "yield break;" or the end of the
    // method is reached in Implementation
    protected virtual void OnExit()
    {
    }

    /// <summary>
    /// TODO
    /// </summary>
    public void NextState()
    {
        if (IsOrphaned)
            return;
        if (!_stateEnumerator.MoveNext())
            OnExit();
    }

    /// <summary>
    /// See comments in <r>StateMachine</r>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [DebuggerDisplay("Result = {Result}")]
    protected class ResultHolder<T>
    {
        StateMachine _stateMachine;

        /// <summary>
        /// TODO
        /// </summary>
        public T Result;

        public ResultHolder(StateMachine stateMachine)
        {
            _stateMachine = stateMachine;
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="result">TODO</param>
        public void OnDone(T result)
        {
            Result = result;
            _stateMachine.NextState();
        }
    }

    protected class AsyncResultHolder
    {
        StateMachine _stateMachine;
        WorkQueue _workQueue;
        Action<IAsyncResult> _endMethod;
        public bool Success;
        public Exception Exception;

        public AsyncResultHolder(StateMachine stateMachine, WorkQueue workQueue,
            Action<IAsyncResult> endMethod, Action<Exception> errorMethod)
        {
            _stateMachine = stateMachine;
            _workQueue = workQueue;
            _endMethod = endMethod;
        }

        public static AsyncResultHolder Run(StateMachine stateMachine, WorkQueue workQueue,
            Action<AsyncCallback> beginMethod, Action<IAsyncResult> endMethod,
            Action<Exception> errorMethod)
        {
            AsyncResultHolder resultHolder = new AsyncResultHolder(stateMachine, workQueue,
                endMethod, errorMethod);
            try
            {
                beginMethod(resultHolder.OnDone);
            }
            catch (Exception ex)
            {
                // note that FaultException derives from CommunicationException
                if ((ex is TimeoutException)
#if !SILVERLIGHT
                     || (ex is EndpointNotFoundException) || (ex is CommunicationException)
#endif
                    )
                {
                    workQueue.Add(delegate
                    {
                        resultHolder.Exception = ex;
                        if (errorMethod != null)
                            errorMethod(ex);
                        resultHolder._stateMachine.NextState();
                    });
                }
                else
                    throw;
            }

            return resultHolder;
        }

        public void OnDone(IAsyncResult asyncResult)
        {
            // note: this is on a different thread!
            bool success;
            try
            {
                _endMethod(asyncResult);
                success = true;
            }
#if !NOCATCH
            catch (Exception ex)
            {
                // note that FaultException derives from CommunicationException
                if ((ex is TimeoutException)
#if !SILVERLIGHT
                    || (ex is EndpointNotFoundException) || (ex is CommunicationException)
#endif
                    )
                {
                    success = false;
                }
                else
                    throw;
            }
#else
            finally
            {
            }
#endif

            _workQueue.Add(delegate
            {
                Success = success;
                _stateMachine.NextState();
            });
        }
    }

    protected class AsyncResultHolder<T>
    {
        StateMachine _stateMachine;
        WorkQueue _workQueue;
        Func<IAsyncResult, T> _endMethod;
        public T Result;
        public Exception Exception;

        public AsyncResultHolder(StateMachine stateMachine, WorkQueue workQueue,
            Func<IAsyncResult, T> endMethod)
        {
            _stateMachine = stateMachine;
            _workQueue = workQueue;
            _endMethod = endMethod;
        }

        public static AsyncResultHolder<T> Run(StateMachine stateMachine, WorkQueue workQueue,
            Action<AsyncCallback> beginMethod, Func<IAsyncResult, T> endMethod,
            Action<Exception> errorMethod)
        {
			AsyncResultHolder<T> resultHolder = new AsyncResultHolder<T>(stateMachine, workQueue,
				endMethod);
            try
            {
                beginMethod(resultHolder.OnDone);
            }
            catch (Exception ex)
            {
                // note that FaultException derives from CommunicationException
                if ((ex is TimeoutException)
#if !SILVERLIGHT
                    || (ex is EndpointNotFoundException) || (ex is CommunicationException)
#endif
                    )
                {
					workQueue.Add(delegate
					{
                        resultHolder.Exception = ex;
                        if (errorMethod != null)
                            errorMethod(ex);
                        resultHolder._stateMachine.NextState();
					});
                }
                else
                    throw;
            }

            return resultHolder;
        }

        public void OnDone(IAsyncResult asyncResult)
        {
            // note: this is on a different thread!
            T result;
            try
            {
                result = _endMethod(asyncResult);
            }
            catch (Exception ex)
            {
                // note that FaultException derives from CommunicationException
                if ((ex is TimeoutException)
#if !SILVERLIGHT
                    || (ex is EndpointNotFoundException) || (ex is CommunicationException)
#endif
                    )
                {
                    result = default(T);
                }
                else
                    throw;
            }

            _workQueue.Add(delegate
            {
                Result = result;
                _stateMachine.NextState();
            });
        }
    }
}

public class EnsureSingleThreaded
{
#if DEBUG
    int _creationThreadId = Thread.CurrentThread.ManagedThreadId;
    string _creationThreadName = Thread.CurrentThread.Name ?? "unnamed";
#endif

    [Conditional("DEBUG")]
    public void Verify()
    {
#if DEBUG
        int currentThreadId = Thread.CurrentThread.ManagedThreadId;
        if (currentThreadId != _creationThreadId)
        {
            string currentThreadName = Thread.CurrentThread.Name ?? "unnamed";
            throw new InvalidOperationException(String.Format(
                "EnsureSingleThreaded.Verify failed: object was created on thread {0} ({1}) but is now running on thread {2} ({3})",
                _creationThreadId, _creationThreadName, currentThreadId, currentThreadName));
        }
#endif
    }
}

/// <summary>
/// Represents a collection of zero or more arguments (name/value pairs).  Can be converted to or
/// from a compact string representation.
/// </summary>
///
public class ParsedArguments
{
    static protected readonly char[] _reservedChars = { ';', '=' };

	Dictionary<string, string> _arguments = new Dictionary<string, string>();

	/// <summary>
	/// The original string that was parsed to initialize the state of this object.
	/// </summary>
	public string StringForm { get; protected set; }

    string StringFormLabel
    {
        get
        {
            if (StringForm.Length > 0)
                return StringForm;
            else
                return "(empty string)";
        }
    }

	protected ParsedArguments()
	{
	}

    // note: an argument value (but not an argument name) may contain an '=' or a ';' but in
    // the latter case the ';' must be changed to ';;' -- this method will convert it back
    // to ';' -- see EncodeArgument
	public ParsedArguments(string stringForm)
	{
        ParseArguments(stringForm);
	}

    protected void ParseArguments(string stringForm)
    {
        // treat null <stringForm> the same as if it were empty
        if (stringForm == null)
            stringForm = String.Empty;

        // initialize object state
        StringForm = stringForm;

        // set <modifiedStringForm> to <stringForm> but with escaped semicolons changed to
        // '\xFFFF'; note that it's important not to let the '\xFFFF' characters be returned by
        // this class, since that character is invalid for XML interchange (which is why it was
        // chosen here)
        string modifiedStringForm = stringForm.Replace(";;", "\xFFFF");

        ParseArgumentsFromModifiedStringForm(modifiedStringForm);
    }

    public static string EncodeArgument(string value)
    {
        return value.Replace(";", ";;");
    }

	public static string Format(params string[] argNameValuePairs) 
	{
        var result = new StringBuilder();
		FormatArguments(argNameValuePairs, result);
        return result.ToString();
	}

	static protected void FormatArguments(string[] argNameValuePairs, StringBuilder result)
	{
        if ((argNameValuePairs.Length & 1) != 0)
        {
            throw new ArgumentException(
			"Expected an even number of name/value pairs",
			"argNameValuePairs");
        }
        for (int index = 0; index < argNameValuePairs.Length; )
        {
            if (index > 0)
                result.Append(';');

            string argName = argNameValuePairs[index++];
            string argValue = argNameValuePairs[index++];
            if (argName.IndexOfAny(_reservedChars) >= 0)
            {
                throw new ArgumentException(
					"Argument name may not contain ';' or '='",
					"argNameValuePairs");
            }

			if (result.Length > 0)
				result.Append(' ');
            result.Append(argName);
            result.Append('=');
            result.Append(EncodeArgument(argValue));
        }
	}

    public string GetOptionalArgument(string argumentName)
    {
        string value;
        _arguments.TryGetValue(argumentName, out value);
        return value;
    }

	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
	public string GetRequiredArgument(string argumentName)
	{
		string value;
        if (!_arguments.TryGetValue(argumentName, out value))
		{
			throw NewFormatException(
				"Missing argument \"{0}\" in: {1}",
				argumentName, StringFormLabel);
		}
        return value; 
	}

	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
    public int GetRequiredIntArgument(string argumentName)
    {
        string stringValue = GetRequiredArgument(argumentName);
        try
        {
            return XmlConvert.ToInt32(stringValue);
        }
        catch (Exception ex)
        {
			if ((ex is FormatException) || (ex is OverflowException))
			{
				throw NewFormatException(
					"Expected argument \"{0}\" to be an integer, but got \"{1}\", in: {2}",
					argumentName, stringValue, StringFormLabel);
			}
			else
				throw;
        }
    }

    // gets an argument of the form "<int>,<int>,...,<int>"
	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
    public int[] GetRequiredIntListArgument(string argumentName)
    {
        string stringValue = GetRequiredArgument(argumentName);
        string[] parts = stringValue.Split(',');
        int[] array = new int[parts.Length];
        try
        {
            for (int index = 0; index < parts.Length; index++)
                array[index] = XmlConvert.ToInt32(parts[index]);
            return array;
        }
        catch (Exception ex)
        {
			if ((ex is FormatException) || (ex is OverflowException))
			{
				throw NewFormatException(
					"Expected argument \"{0}\" to be a list of integers, but got \"{1}\", in: {2}",
					argumentName, stringValue, StringFormLabel);
			}
			else
				throw;
        }
    }

	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
    /// <summary>
    /// Returns the value whose argument is a list of strings.  When the list is constructed,
    /// items must be separated by vertical bar (|) characters; if an item needs to contain a
    /// vertical bar, it should be doubled -- or use <r>FormatStringListItem</r>.
    /// </summary>
    /// <param name="argumentName"></param>
    /// <returns></returns>
    public string[] GetRequiredStringListArgument(string argumentName)
    {
        string stringValue = GetRequiredArgument(argumentName);

        // change <stingValue> so that escaped "|" are temporarily changed to '\xFFFF'
        stringValue = stringValue.Replace("||", "\xFFFF");

        string[] parts = stringValue.Split('|');
        for (int index = 0; index < parts.Length; index++)
        {
            // change '\xFFFF' back to "|"
            parts[index] = parts[index].Replace("\xFFFF", "|");
        }

        return parts;
    }

    // to use this: create an empty StringBuilder, and then call this method once for every item
    // to add to the list; the result can be given to <r>ParsedCommand.Format</r> as an
    // argument
	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand

    /// <summary>
    /// TODO
    /// </summary>
    /// <param name="list">TODO</param>
    /// <param name="item">TODO</param>
    public static void FormatStringListItem(StringBuilder list, string item)
    {
        if (list.Length > 0)
            list.Append('|');
        list.Append(item.Replace("|", "||"));
    }

    bool ConvertArgumentToBoolean(string argumentName, string stringValue)
    {
        try
        {
            return XmlConvert.ToBoolean(stringValue);
        }
        catch (FormatException)
        {
            throw NewFormatException(
				"Expected argument \"{0}\" to be \"true\" or \"false\", but got \"{1}\", in: {2}",
                argumentName, stringValue, StringFormLabel);

        }
    }

	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
    public bool GetOptionalBooleanArgument(string argumentName, bool defaultValue)
    {
        string stringValue = GetOptionalArgument(argumentName);
        if (stringValue == null)
            return defaultValue;
        return ConvertArgumentToBoolean(argumentName, stringValue);
    }

	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
    public bool GetRequiredBooleanArgument(string argumentName)
    {
        string stringValue = GetRequiredArgument(argumentName);
        return ConvertArgumentToBoolean(argumentName, stringValue);
    }

	// exceptions: FormatException for ParsedArguments or ParsedCommand; SyncException for ParsedSyncNodeCommand
	public Guid GetRequiredGuidArgument(string argumentName)
	{
		string stringValue = GetRequiredArgument(argumentName);
		try
		{
			return XmlConvert.ToGuid(stringValue);
		}
		catch (FormatException)
		{
			throw NewFormatException(
				"Expected argument \"{0}\" to be a GUID, but got \"{1}\", in: {2}",
				argumentName, stringValue, StringFormLabel);
		}
	}

	// "modified" means that escaped semicolons (;;) were changed to '\0xFFFF'
	protected void ParseArgumentsFromModifiedStringForm(string modifiedStringForm)
	{
        modifiedStringForm = modifiedStringForm.Trim();
        if (modifiedStringForm.Length == 0)
            return;

		string[] pairs = modifiedStringForm.Split(';');
		foreach (string rawPairString in pairs)
		{
			string pairString = rawPairString.Trim(); // e.g. foo=whatever
			int equalsIndex = pairString.IndexOf('=');
			string argName;
			if ((equalsIndex < 0) ||
				((argName = pairString.Substring(0, equalsIndex)).Trim().Length == 0)) 
			{
				throw NewFormatException(
					"Expecting \"parameter=value\", got \"{0}\", in: {1}",
					pairString, StringFormLabel);
			}
			string argValue = pairString.Substring(equalsIndex + 1).Trim()
				.Replace('\xFFFF', ';');
			try
			{
				_arguments.Add(argName, argValue);
			}
			catch (ArgumentException)
			{
				throw NewFormatException(
					"Duplicate parameter name \"{0}\" in: {1}",
					argName, StringFormLabel);
			}
		}
	}

	protected virtual Exception NewFormatException(string format, params object[] args)
	{
		return new FormatException(String.Format(format, args));
	}

    public override string ToString()
    {
        return StringForm;
    }
}

/// <summary>
/// Represents a command name (a string) plus a collection of zero or more arguments (name/value
/// pairs).  Can be converted to or from a compact string representation.
/// </summary>
///
public class ParsedCommand : ParsedArguments
{
	public string Name { get; private set; }

    // note: an argument value (but not an argument name) may contain an '=' or a ';' but in
    // the latter case the ';' must be changed to ';;' -- this method will convert it back
    // to ';' -- see EncodeArgument
	public ParsedCommand(string stringForm)
	{
		// initialize object state
		StringForm = stringForm;
        
        // set <modifiedStringForm> to <stringForm> but with escaped semicolons changed to
		// '\xFFFF'; note that it's important not to let the '\xFFFF' characters be returned by
		// this class, since that character is invalid for XML interchange (which is why it was
		// chosen here)
        string modifiedStringForm = stringForm.Replace(";;", "\xFFFF");

        int colonIndex = modifiedStringForm.IndexOf(':');
        if (colonIndex < 0)
            Name = modifiedStringForm.Trim();
        else
		{
            Name = modifiedStringForm.Substring(0, colonIndex).Trim();
			ParseArgumentsFromModifiedStringForm(modifiedStringForm.Substring(colonIndex + 1));
		}
	}

    public static string Format(string commandName, params string[] argNameValuePairs)
    {
        if (commandName.IndexOfAny(_reservedChars) >= 0)
        {
            throw new ArgumentException("Command name may not contain ';' or '='", "commandName");
        }

        if (argNameValuePairs.Length == 0)
            return commandName;

        var result = new StringBuilder();
        result.Append(commandName);
        result.Append(':');
		FormatArguments(argNameValuePairs, result);
        return result.ToString();
    }
}

[DebuggerDisplay("{DebuggerDisplay}")]
public class XmlElementInfo
{
    XmlReader _xmlReader;
    List<string> _path;

    public static IEnumerable<XmlElementInfo> EnumerateElements(XmlReader reader)
    {
        var path = new List<string>();
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                path.Add(reader.Name);

                var elementInfo = new XmlElementInfo()
                {
                    _xmlReader = reader,
                    _path = path
                };
                yield return elementInfo;
                elementInfo.Orphan();

                // note that if the element contained Base64 data and GetContentAsBytes was
                // called, then when "yield return" is done the current element will be
                // the end element
                if (reader.IsEmptyElement || (reader.NodeType == XmlNodeType.EndElement))
                {
                    // return the end element
                    path[path.Count - 1] = "/" + reader.Name;
                    elementInfo = new XmlElementInfo()
                    {
                        _xmlReader = reader,
                        _path = path
                    };
                    yield return elementInfo;
                    elementInfo.Orphan();

                    path.RemoveAt(path.Count - 1);
                }
            }
            else
            if (reader.NodeType == XmlNodeType.EndElement)
            {
                // if we hit an end element that corresponds to a begin element that was
                // encountered before the start of this method, quit now
                if (path.Count == 0)
                    yield break;

                // return the end element
                path[path.Count - 1] = "/" + reader.Name;
                var elementInfo = new XmlElementInfo()
                {
                    _xmlReader = reader,
                    _path = path
                };
                yield return elementInfo;
                elementInfo.Orphan();

                path.RemoveAt(path.Count - 1);
            }
        }
    }

    /// <summary>
    /// "Orphans" this <r>ElementInfo</r>, so it can't be used after this point.  This is done
    /// when <r>_xmlREader</r> and <r>_path</r> will soon refer to something else.
    /// </summary>
    void Orphan()
    {
        _xmlReader = null;
        _path = null;
    }

    public string Name
    {
        get
        {
            VerifyNotOrphan();
            return _path[_path.Count - 1];
        }
    }

    public IList<string> Path
    {
        get
        {
            VerifyNotOrphan();
            return _path;
        }
    }

    public string PathAsString
    {
        get
        {
            VerifyNotOrphan();
            var result = new StringBuilder(100);
            foreach (string part in Path)
            {
                if (result.Length > 0)
                    result.Append('/');
                result.Append(part);
            }
            return result.ToString();
        }
    }

    public string GetRequiredAttribute(string attributeName)
    {
        VerifyNotOrphan();
        string value = _xmlReader.GetAttribute(attributeName);
        if (value == null)
        {
            throw new InvalidOperationException(String.Format(
                "XML element <{0}> has no \"{1}\" attribute", Name, attributeName));
        }

        return value;
    }

    public int GetRequiredIntAttribute(string attributeName)
    {
        string stringValue = GetRequiredAttribute(attributeName);
        try
        {
            return XmlConvert.ToInt32(stringValue);
        }
        catch (Exception ex)
        {
            if ((ex is FormatException) || (ex is OverflowException))
            {
                throw new InvalidOperationException(String.Format(
                    "XML element <{0}> has \"{1}\" attribute with value \"{2}\"; expecting an integer value",
                    Name, attributeName, stringValue));
            }
            else
                throw;
        }
    }

    public double GetRequiredDoubleAttribute(string attributeName)
    {
        string stringValue = GetRequiredAttribute(attributeName);
        try
        {
            return XmlConvert.ToDouble(stringValue);
        }
        catch (Exception ex)
        {
            if ((ex is FormatException) || (ex is OverflowException))
            {
                throw new InvalidOperationException(String.Format(
                    "XML element <{0}> has \"{1}\" attribute with value \"{2}\"; expecting a numeric value",
                    Name, attributeName, stringValue));
            }
            else
                throw;
        }
    }

    public bool GetRequiredBoolAttribute(string attributeName)
    {
        string stringValue = GetRequiredAttribute(attributeName);
        try
        {
            return XmlConvert.ToBoolean(stringValue);
        }
        catch (Exception ex)
        {
            if (ex is FormatException)
            {
                throw new InvalidOperationException(String.Format(
                    "XML element <{0}> has \"{1}\" attribute with value \"{2}\"; expecting \"true\" or \"false\"",
                    Name, attributeName, stringValue));
            }
            else
                throw;
        }
    }

    public T GetRequiredEnumAttribute<T>(string attributeName)
    {
        string stringValue = GetRequiredAttribute(attributeName);
        try
        {
            return (T)Enum.Parse(typeof(T), stringValue, false);
        }
        catch (ArgumentException)
        {
            throw new InvalidOperationException(String.Format(
                "XML element <{0}> has \"{1}\" attribute with value \"{2}\"; expecting a value of type {3}",
                Name, attributeName, stringValue, typeof(T).Name));
        }
    }

    public byte[] GetContentAsBytes()
    {
        VerifyNotOrphan();

        if ((_xmlReader.NodeType != XmlNodeType.Element) ||
            !_xmlReader.Read() || (_xmlReader.NodeType != XmlNodeType.Text))
            throw new InvalidOperationException("Incorrect state");

        byte[] buffer = new byte[10 * 1024];
        int totalBytesRead = 0;
        while (_xmlReader.NodeType == XmlNodeType.Text)
        {
            int capacity = buffer.Length - totalBytesRead;
            if (capacity * 2 < totalBytesRead)
            {
                byte[] newBuffer = new byte[buffer.Length * 2];
                Buffer.BlockCopy(buffer, 0, newBuffer, 0, totalBytesRead);
                buffer = newBuffer;
                capacity = buffer.Length - totalBytesRead;
            }
            int bytesRead = _xmlReader.ReadContentAsBase64(buffer, totalBytesRead, capacity);
            if (bytesRead == 0)
                break;
            totalBytesRead += bytesRead;
        }

        if (totalBytesRead < buffer.Length)
        {
            byte[] newBuffer = new byte[totalBytesRead];
            Buffer.BlockCopy(buffer, 0, newBuffer, 0, totalBytesRead);
            buffer = newBuffer;
        }

        return buffer;
    }

    // careful: the returned XmlReader is only valid until the enumeration continues
    public XmlReader XmlReader
    {
        get
        {
            VerifyNotOrphan();
            return _xmlReader;
        }
    }

    object DebuggerDisplay
    {
        get
        {
            var buffer = new StringBuilder(1000);
            var settings = new XmlWriterSettings();
            settings.OmitXmlDeclaration = true;
            using (XmlWriter writer = XmlWriter.Create(buffer, settings))
            {
                writer.WriteStartElement(Name);
                if (_xmlReader.MoveToFirstAttribute())
                {
                    while (true)
                    {
                        writer.WriteAttributeString(_xmlReader.Name, _xmlReader.NamespaceURI,
                            _xmlReader.Value);
                        if (!_xmlReader.MoveToNextAttribute())
                            break;
                    }
                    _xmlReader.MoveToElement();
                }
                if (!String.IsNullOrEmpty(_xmlReader.Value))
                    writer.WriteString(_xmlReader.Value);
                if (!_xmlReader.IsEmptyElement)
                    writer.WriteString("...");
                writer.WriteEndElement();
            }
            return new EncapsulatedString(buffer.ToString());
        }
    }

    void VerifyNotOrphan()
    {
        if (_xmlReader == null)
        {
            throw new InvalidOperationException(
                "XmlElementInfo was used after enumeration continued");
        }
    }
}


/// <summary>
/// Generic implementation of IAsyncResult.
/// </summary>
///
public class GenericAsyncResult : IAsyncResult, IDisposable
{
	AsyncCallback _asyncCallback;
	object _asyncState;
	bool _isCompleted = false;
	ManualResetEvent _event;
    public object Result { get; set; }

	public GenericAsyncResult(AsyncCallback asyncCallback, object asyncState)
	{
		_asyncCallback = asyncCallback;
		_asyncState = asyncState;
	}

	public void Complete()
	{
		_isCompleted = true;

		// tell caller we're done
		_asyncCallback(this);
	}

	bool IAsyncResult.IsCompleted
	{
		get
		{
			return _isCompleted;
		}
	}

	WaitHandle IAsyncResult.AsyncWaitHandle
	{
		get
		{
			_event = new ManualResetEvent(false);
			return _event;
		}
	}

	bool IAsyncResult.CompletedSynchronously
	{
		get
		{
			return false;
		}
	}

	object IAsyncResult.AsyncState
	{
		get
		{
			return _asyncState;
		}
	}

	void IDisposable.Dispose()
	{
		if (_event != null)
		{
			_event.Close();
			_event = null;
		}
	}
}


/// <summary>
/// Implements IList&lt;T&gt; given a count of items and a delegate which returns an item given
/// its index from 0 to count-1 inclusive.
/// </summary>
///
/// <typeparam name="T">The type of item in the list.</typeparam>
///
public class SimpleList<T> : IList<T>
{
    int _count;
    Func<int, T> _getItem;

    public SimpleList(int count, Func<int, T> getItem)
    {
        _count = count;
        _getItem = getItem;
    }

    int IList<T>.IndexOf(T item)
    {
        return FindIndexOf(item);
    }

    void IList<T>.Insert(int index, T item)
    {
        throw NewReadOnlyException();
    }

    void IList<T>.RemoveAt(int index)
    {
        throw NewReadOnlyException();
    }

    T IList<T>.this[int index]
    {
        get
        {
            return _getItem(index);
        }
        set
        {
            throw NewReadOnlyException();
        }
    }

    void ICollection<T>.Add(T item)
    {
        throw NewReadOnlyException();
    }

    void ICollection<T>.Clear()
    {
        throw NewReadOnlyException();
    }

    bool ICollection<T>.Contains(T item)
    {
        return FindIndexOf(item) >= 0;
    }

    void ICollection<T>.CopyTo(T[] array, int arrayIndex)
    {
        for (int index = 0; index < _count; index++)
            array[arrayIndex + index] = _getItem(index);
    }

    int ICollection<T>.Count
    {
        get { return _count; }
    }

    bool ICollection<T>.IsReadOnly
    {
        get { return true; }
    }

    bool ICollection<T>.Remove(T item)
    {
        throw NewReadOnlyException();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return new SimpleListEnumerator<T>(_count, _getItem);
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return new SimpleListEnumerator<T>(_count, _getItem);
    }

    NotSupportedException NewReadOnlyException()
    {
        return new NotSupportedException("List is read-only");
    }

    int FindIndexOf(T item)
    {
        for (int index = 0; index < _count; index++)
        {
            if (item.Equals(_getItem(index)))
                return index;
        }
        return -1;
    }

    class SimpleListEnumerator<U> : IEnumerator<U>
    {
        int _count;
        Func<int, U> _getItem;
        int _index = -1;

        public SimpleListEnumerator(int count, Func<int, U> getItem)
        {
            _count = count;
            _getItem = getItem;
        }

        U IEnumerator<U>.Current
        {
            get { return _getItem(_index); }
        }

        void IDisposable.Dispose()
        {
        }

        object System.Collections.IEnumerator.Current
        {
            get { return _getItem(_index); }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            if (_index >= _count - 1)
                return false;
            _index++;
            return true;
        }

        void System.Collections.IEnumerator.Reset()
        {
            _index = -1;
        }
    }
}

}
